看下面的例子:https://onlinegdb.com/Hkg6iQ3ZNI
#include <iostream>
#include <utility>
#include <type_traits>
class A
{
public:
A(int v=-10):v_(v){}
void print()
{
std::cout << "called A: " << v_ << std::endl;
}
private:
int v_;
};
void f(int v)
{
std::cout << "called f: " << v << std::endl;
}
template<typename T,typename ... Args>
void run(A&& a,
T&& t,
Args&& ... args)
{
a.print();
t(std::forward<Args>(args)...);
}
template<typename T,typename ... Args>
void run(T&& t,
Args&& ... args)
{
run(A(),
std::forward<T>(t),
std::forward<Args>(args)...);
}
int main()
{
int v_function=1;
int v_a = 2;
run(f,v_function);
return 0;
}
上面的代码编译、运行和打印(如预期的那样):called A: -10
called f: 1
但如果主函数修改为:
int main()
{
int v_function=1;
int v_a = 2;
run(f,v_function);
// !! added lines !!
A a(v_a);
run(a,f,v_function);
return 0;
}
然后编译失败并出现错误:main.cpp:30:6: error: no match for call to ‘(A) (void (&)(int), int&)’
t(std::forward(args)...);
~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
这似乎表明即使 A 的实例作为第一个参数传递,重载函数
void(*)(T&&,Args&&...)
被称为,而不是void(*)(A&&,T&&,Args&&...)
最佳答案
和
template<typename T,typename ... Args>
void run(A&& a,
T&& t,
Args&& ... args)
a
不是转发引用,而是右值引用。这意味着当你做 run(a,f,v_function);
该函数将不会被选中,因为 a
是一个左值,不能绑定(bind)到右值引用。有两种快速方法可以解决此问题。首先,使用 std::move
在 a
像run(std::move(a),f,v_function);
但这不是很好。
a
实际上并没有在函数中移动,所以你有点违反了最小惊喜原则。第二个选项是使
A
在函数中是模板类型,因此它成为转发引用,然后您可以将其限制为 A
类型像template<typename A_, typename T,typename ... Args, std::enable_if_t<std::is_same_v<std::decay_t<A_>, A>, bool> = true>
void run(A_&& a,
T&& t,
Args&& ... args)
{
a.print();
t(std::forward<Args>(args)...);
}
关于时间:2019-05-01 标签:c++: variadic template and function overloading,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60383472/