这个电话:
Bar<Foo> bar2{bar1};
其过载集中有两个候选者:
Bar(const Bar&);
Bar(Bar&); // Args... = {Bar&}
确定一种转换序列是否优于另一种转换序列的方法之一是来自 [over.ics.rank]:
标准转换序列 S1 是比标准转换序列更好的转换序列
S2 如果
— [...]
— S1和S2是引用绑定(8.5.3),引用引用的类型是相同的
顶级类型除外cv-限定符,以及 S2 初始化的引用所指的类型
更多的是cv-比 S1 初始化的引用所引用的类型限定。[ 例子:
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)
If Args...
是其中之一Bar
, Bar&
, Bar&&
, const Bar&
, then typelist<decay_t<Args>...>
将typelist<Bar>
- 这是我们想要排除的情况。任何其他集合Args...
会被允许就好了。