模板函数作为模板参数

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 引用?我做错了什么吗?

1个回答

7
我认为像 T&& 这样的函数参数是一种可以绑定到 [rvalues 和 lvalues] 的特殊情况吗?
是的。这基本上意味着模板可以对 lvalues 和 rvalues 进行不同的实例化。
然而... 当你在 test2<string> 中明确地将 T 设置为 string 时,你选择了一个特定的实例化:void test2(string&&, int)string&& 不再是那个特殊情况了。 string&& 只能绑定到 string rvalues。没有一个实例化可以同时绑定到 rvalues 和 lvalues。
总的来说,我建议不要显式传递函数模板参数(除非那是有意为之,比如 std::forwardstd::make_unique)。
在这种情况下,你可以强制使用绑定到 lvalues 的一个实例化。例如,像 flip(test2<string&>, 42, s); 这样的语句将实例化 void test2(string&, int)
如果你真的想传递一个可以接受 lvalues 和 rvalues 的参数给 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);

这很有道理。我已经尝试调用 flip(test2, 42, s),但注意到当传递 test2 函数指针时无法知道特化的部分,因此尝试传递 test2<string>。我错过的部分是现在我的函数不再是一个模板,这意味着 T&& 不再存在。谢谢! - Timo Türschmann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接