简体   繁体   English

模板函数作为模板参数

[英]Template function as template argument

I'm learning about templates and tried to implement this method: 我正在学习模板并尝试实现此方法:

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

It takes a function and two parameters and calls the given function with the two parameters flipped. 它需要一个函数和两个参数,并在翻转两个参数的情况下调用给定的函数。

It works fine with function such as: 它的功能很好,例如:

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

When I tried this function: 当我尝试这个功能时:

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

With: 附:

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

The compiler (g++ 4.7.1) tells me: 编译器(g ++ 4.7.1)告诉我:

error: cannot bind 'std::basic_string' lvalue to 'std::basic_string&&' 错误:无法将'std :: basic_string'左值绑定到'std :: basic_string &&'

I thought that a function parameter such as T&& was a special case that can bind to rvalue and lvalue references? 我认为像T&&这样的函数参数是一个特殊情况,可以绑定到rvaluelvalue引用? What am I doing wrong? 我究竟做错了什么?

I thought that a function parameter such as T&& was a special case that can bind to [rvalues and lvalues]? 我认为函数参数如T&&是一个特殊情况,可以绑定到[rvalues和lvalues]?

It is. 它是。 It basically means the template can have different instantiations for lvalues and for rvalues. 它基本上意味着模板可以为左值和右值具有不同的实例。

However... When you explicitly make T be string in test2<string> , you are picking one particular instantiation: void test2(string&&, int) . 但是......当您在test2<string>明确地使Tstring时,您将选择一个特定的实例: void test2(string&&, int) string&& is no longer that special case. string&&不再是那种特殊情况。 string&& can only bind to string rvalues. string&&只能绑定到字符串rvalues。 There isn't one instantiation that binds to both rvalues and lvalues. 没有一个实例可以绑定rvalues和lvalues。

In general, I'd recommend against explicitly passing function template parameters (unless those are intended, like std::forward or std::make_unique ). 一般来说,我建议不要显式传递函数模板参数(除非这些参数是有意的,比如std::forwardstd::make_unique )。

In this case, you could instead force one of the instantiations that binds to lvalues. 在这种情况下,您可以改为强制绑定到左值的实例化之一。 Something like flip(test2<string&>, 42, s); flip(test2<string&>, 42, s);这样的东西flip(test2<string&>, 42, s); , which will instantiate void test2(string&, int) . ,它将实例化void test2(string&, int)

If you really want to pass an argument to flip that can accept both lvalues and rvalues, you need a polymorphic function object: 如果你真的想传递一个可以接受左值和右值的flip参数,你需要一个多态函数对象:

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

The key here is that the decision of which specialisation to use is not made when passing the argument, but only later on when that argument is used. 这里的关键是,在传递参数时,不会决定使用哪种特化,而是在稍后使用该参数时。

For completeness, in C++14 you can actually create anonymous polymorphic function objects with the new lambda syntax: 为了完整起见,在C ++ 14中,您实际上可以使用新的lambda语法创建匿名多态函数对象:

auto test2 = [](auto&& a, int) {};
flip(test2, 42, s);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM