4

我正在学习模板并尝试实现此方法:

template <typename Func, typename Left, typename Right>
void flipArgs(Func* function, Left&& leftArg, Right&& rightArg) {
    function(std::forward<Right>(rightArg), std::forward<Left>(leftArg));
}

它接受一个函数和两个参数,并在两个参数翻转的情况下调用给定的函数。

它适用于以下功能:

void test1(std::string, int) {
}

当我尝试这个功能时:

template <typename T>
void test2(T&& a, int) {
}

和:

string s("test");
flip(test2<string>, 42, s);

编译器(g++ 4.7.1)告诉我:

错误:无法将“std::basic_string”左值绑定到“std::basic_string&&”

我认为一个函数参数T&&是一个可以绑定rvaluelvalue引用的特殊情况?我究竟做错了什么?

4

1 回答 1

7

我认为像这样的函数参数T&&是可以绑定到 [rvalues and lvalues] 的特殊情况?

这是。这基本上意味着模板可以对左值和右值有不同的实例化。

但是...当您明确地 make Tbe stringin 时test2<string>,您正在选择一个特定的实例化:void test2(string&&, int). string&&不再是那种特例。string&&只能绑定到字符串右值。没有一个实例可以同时绑定到右值和左值。

一般来说,我建议不要显式传递函数模板参数(除非那些是有意的,比如std::forwardor std::make_unique)。

在这种情况下,您可以改为强制绑定到左值的实例之一。类似的东西flip(test2<string&>, 42, s);,它将实例化void test2(string&, int)

如果你真的想传递一个flip可以接受左值和右值的参数,你需要一个多态函数对象:

struct test2 {
    template <typename T>
    void operator()(T&& a, int) const {
    }
};
flip(test2{}, 42, s);

这里的关键是,在传递参数时不会决定使用哪个专业化,而只是在稍后使用该参数时做出。

为了完整起见,在 C++14 中,您实际上可以使用新的 lambda 语法创建匿名多态函数对象:

auto test2 = [](auto&& a, int) {};
flip(test2, 42, s);
于 2013-10-22T11:41:09.720 回答