std::forward 和运算符()

Aco*_*orn 3 c++ templates

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

#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;
}
Run Code Online (Sandbox Code Playgroud)

这对我来说都是有意义的,除了一件事struct identity:. 它接受 T 类型的 rhs,称为 x、cool 等等。但是当identity被调用时,实际上没有任何东西传递到身份中。

template<typename F>
void then(const F& f){
    f(identity());
}
Run Code Online (Sandbox Code Playgroud)

上面,f 调用identity,但没有将任何内容传递给identity。然而,identity 返回转发的参数(在我的例子中,是一个 std::string),并弹出字符串的最后一个字符。当身份本身没有传递给它来转发的参数时,它如何返回转发的参数?

Bar*_*rry 5

f不调用identity-f使用 的实例调用identity。浏览一下这里的两个案例:

static_if<std::is_same<std::string, T>::value>([&](auto f){
    f(value).pop_back();
}).else_([&](auto f){
    --f(value);
});
Run Code Online (Sandbox Code Playgroud)

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

如果T不是std::string,那么我们实例化一个不执行任何操作statement<false>的对象then(),并使用 的else_()实例调用 lambda identity。再次f(value)是正义value和我们所做的--value


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

最好实现它,以便将参数实际传递给 lambda。