首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >std::forward和operator()

std::forward和operator()
EN

Stack Overflow用户
提问于 2016-06-13 00:22:31
回答 3查看 233关注 0票数 3

我一直在考虑为我的C++项目编写一个C++,我偶然发现了以下代码:

代码语言:javascript
复制
#include <iostream>
using namespace std;

namespace static_if_detail {

struct identity {
    template<typename T>
    T operator()(T&& x) const {
        return std::forward<T>(x);
    }
};

template<bool Cond>
struct statement {
    template<typename F>
    void then(const F& f){
        f(identity());
    }

    template<typename F>
    void else_(const F&){}
};

template<>
struct statement<false> {
    template<typename F>
    void then(const F&){}

    template<typename F>
    void else_(const F& f){
        f(identity());
    }
};

} //end of namespace static_if_detail

template<bool Cond, typename F>
static_if_detail::statement<Cond> static_if(F const& f){
    static_if_detail::statement<Cond> if_;
    if_.then(f);
    return if_;
}

template<typename T>
void decrement_kindof(T& value){
    static_if<std::is_same<std::string, T>::value>([&](auto f){
        f(value).pop_back();
    }).else_([&](auto f){
        --f(value);
    });
}


int main() {
    // your code goes here
    std::string myString{"Hello world"};
    decrement_kindof(myString);
    std::cout << myString << std::endl;
    return 0;
}

这一切对我来说都是有意义的,除了一件事:struct identity中的重载操作符()。它采用了一个名为x,酷和所有的T型rhs。但是当identity被调用时,实际上没有任何东西被传递给身份。

代码语言:javascript
复制
template<typename F>
void then(const F& f){
    f(identity());
}

上面,f调用标识,但没有传递任何标识。然而,identity返回转发的参数(在我的例子中,是一个std:: string ),并弹出字符串的最后面的字符。如果标识本身没有传递给转发的参数,那么标识如何返回转发的参数?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-06-13 00:37:10

f不调用identity -- f是用identity实例调用的。在这里遍历这两个案例:

代码语言:javascript
复制
static_if<std::is_same<std::string, T>::value>([&](auto f){
    f(value).pop_back();
}).else_([&](auto f){
    --f(value);
});

如果Tstd::string,那么我们实例化一个statement<true>,它的then()使用identity实例调用传入函数。第一个lambda的参数,f,将是identity类型的-因此f(value)实际上只是value,我们做value.pop_back()

如果T不是std::string,那么我们实例化一个statement<false>,它的then()什么也不做,它的else_()identity实例调用lambda。再说一遍,f(value)只是value,我们做的是--value

这是static_if的一个非常令人困惑的实现,因为lambda中的f总是一个identity。这是必要的,因为我们不能直接使用value (不能编写value.pop_back(),因为那里没有依赖的名称,所以编译器会很高兴地确定它对于整数的格式不正确),所以我们只是将value的所有用法包装在一个依赖函数对象中,以延迟实例化(f(value)依赖于f,所以在提供f之前不能实例化--如果函数没有调用,就不会发生这种情况)。

更好的做法是实现它,以便实际将参数传递给lambda。

票数 5
EN

Stack Overflow用户

发布于 2016-06-13 00:56:37

代码语言:javascript
复制
template<typename F>
void then(const F& f){
  f(identity());
}

更具可读性,因为

代码语言:javascript
复制
template<typename F>
void then(const F& f){
  f(identity{});
}

它们正在构造标识对象,而不是调用标识对象。

这里的诀窍是,即使函数从未实例化,模板函数的非依赖部分也必须是有效的。

因此,当值是整数时,说value.pop_back()在lambda中是无效的。

通过将identity{}传递给thenelse的情况之一,我们可以避免这个问题。

语句f(value)生成依赖类型。因此,只有当实际实例化了lambda的模板operator()时,它才需要有效(还必须有一些可能的f使其有效,但这是一个角的情况)。

由于我们只实例化条件告诉我们的路径,所以只要f(value)在所获取的分支中有效,它几乎可以以任何我们想要的方式使用。

我会称f为一个更好的名字,比如safeguardvarmagic,而不是f。在简洁的代码中使用两个f的不同上下文增加了混乱。

票数 1
EN

Stack Overflow用户

发布于 2016-06-13 00:53:47

让我们来看看,您的Condstatic_if中是true,因此,将使用主模板类.

代码语言:javascript
复制
template<bool Cond>
struct statement {
    template<typename F>
    void then(const F& f){
        f(identity());
    }

    template<typename F>
    void else_(const F&){}
};

回想一下,您的调用函数是:

代码语言:javascript
复制
static_if<std::is_same<std::string, T>::value>
(
   [&](auto f){ //This is the lamda passed, it's a generic lambda
        f(value).pop_back();
    }
).else_(
   [&](auto f){
        --f(value);
    }
);

在下面的应用函数中,F泛型lambda的一种类型(意思是,您可以使用任何类型调用f )。

代码语言:javascript
复制
template<typename F>
void then(const F& f){
    f(identity());
}

identity()创建一个类型为identity的对象,然后将其作为参数传递,以调用为您的泛型lambda。

代码语言:javascript
复制
 [&](auto f){ //This is the lamda passed, it's a generic lambda
        f(value).pop_back();
    }

但是回想一下,f是一个identity类型的对象,它有一个模板化的call ()操作符,它基本上返回传递给它的对象。

所以,我们就像这样:

代码语言:javascript
复制
void decrement_kindof(std::string& value){
    static_if<std::is_same<std::string, std::string>::value>([&](auto f){
        f(value).pop_back();
    }).else_([&](auto f){
        --f(value);
    });
});

减为:

代码语言:javascript
复制
void decrement_kindof(std::string& value){
    static_if<true>([&](auto f){
        f(value).pop_back();
    }).else_([&](auto f){
        --f(value);
    });
});

减为:

代码语言:javascript
复制
void decrement_kindof(std::string& value){
    static_if<true>(
        [&](identity ident){
             auto&& x = ident(value); //x is std::string()
             x.pop_back();
       } (identity())  //<-- the lambda is called

    ).else_(
        [&](auto f){    //This is not evaluated, because it's not called by the primary template of `statement`
            --f(value);
        }
    );   
});
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37780389

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档