以下代码无法编译:
#include <iostream>
#include <utility>
struct Foo
{
Foo() { std::cout << "Foo()" << std::endl; }
Foo(int) { std::cout << "Foo(int)" << std::endl; }
};
template <typename T>
struct Bar
{
Foo foo;
Bar(const Bar&) { std::cout << "Bar(const Bar&)" << std::endl; }
template <typename... Args>
Bar(Args&&... args) : foo(std::forward<Args>(args)...)
{
std::cout << "Bar(Args&&... args)" << std::endl;
}
};
int main()
{
Bar<Foo> bar1{};
Bar<Foo> bar2{bar1};
}
编译器错误提示我,编译器正在尝试使用可变参数模板构造函数而不是复制构造函数:
prog.cpp: In instantiation of 'Bar<T>::Bar(Args&& ...) [with Args = {Bar<Foo>&}; T = Foo]':
prog.cpp:27:20: required from here
prog.cpp:18:55: error: no matching function for call to 'Foo::Foo(Bar<Foo>&)'
Bar(Args&&... args) : foo(std::forward<Args>(args)...)
为什么编译器会这样做以及如何解决?
这个电话:
Bar<Foo> bar2{bar1};
在其重载集中有两个候选:
Bar(const Bar&);
Bar(Bar&); // Args... = {Bar&}
从[over.ics.rank]确定一种转换顺序是否比另一种转换顺序更好的方法之一是:
如果满足以下条件,则标准转换序列S1比标准转换序列S2更好。
— [...]
— S1和S2是引用绑定(8.5.3),引用所引用的类型是相同的类型(顶级cv -qualifiers除外)以及引用由S2初始化的类型引用比由S1初始化的引用所引用的类型更具cv资格。[示例:int f(const int &); int f(int &); int g(const int &); int g(int); int i; int j = f(i); // calls f(int &) int k = g(i); // ambiguous
—结束示例]
转发引用可变参数构造函数是更好的匹配项,因为其引用绑定(Bar&
)的cv限定性低于复制构造函数的引用绑定(const Bar&
)。
就解决方案而言,您可以随时将其排除在候选集之外Args...
,而应该使用SFINAE调用该副本或移动构造函数:
template <typename... > struct typelist;
template <typename... Args,
typename = std::enable_if_t<
!std::is_same<typelist<Bar>,
typelist<std::decay_t<Args>...>>::value
>>
Bar(Args&&... args)
如果Args...
是一Bar
,Bar&
,Bar&&
,const Bar&
,那么typelist<decay_t<Args>...>
将是typelist<Bar>
-这就是我们要排除的情况下。任何其他设置Args...
都可以。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句