Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ c++;11具有可变通用引用的构造函数和复制构造函数_C++_Templates_C++11_Constructor_C++14 - Fatal编程技术网

C++ c++;11具有可变通用引用的构造函数和复制构造函数

C++ c++;11具有可变通用引用的构造函数和复制构造函数,c++,templates,c++11,constructor,c++14,C++,Templates,C++11,Constructor,C++14,如果我们有带有通用引用参数的构造函数,如何声明复制构造函数 struct记录{ 模板 显式记录(参考&&…参考){ cout在您的示例中,转发引用与Record&一起使用 因此,您可以为记录&添加额外的重载(转发到复制构造函数): Record(Record&other):Record(static_cast(other)){ 或使用转发引用的sFiAe。 < P>这是一个很坏的做法,在转发引用上超载(见有效的现代C++,项目26)。它们往往会因为过载解决规则而吞没所有传递给它们的信息。 在

如果我们有带有通用引用参数的构造函数,如何声明复制构造函数

struct记录{
模板
显式记录(参考&&…参考){

cout在您的示例中,转发引用与
Record&
一起使用

因此,您可以为
记录&
添加额外的重载(转发到复制构造函数):

Record(Record&other):Record(static_cast(other)){

或使用转发引用的sFiAe。

< P>这是一个很坏的做法,在转发引用上超载(见有效的现代C++,项目26)。它们往往会因为过载解决规则而吞没所有传递给它们的信息。

在您的示例中,您正在用非常量
记录
对象构造一个
记录
对象,这就是您的复制ctor无法执行的原因

分派给复制构造函数,因为无法为
记录实例化模板&


如果您发现自己经常这样做(不推荐),您可以通过定义一个类型特征来完成SFINAE,从而消除一些混乱

template<class T1, class T2, class... Refs>
using no_copy_ctor = typename std::enable_if <
    !std::is_same<T1, T2>::value || sizeof...(Refs)>::type;
模板
使用no\u copy\u ctor=typename std::enable\u if<
!std::is_same::value | | sizeof…(参考文献)>::type;
因此,将上述内容写成

template<class Ref1, class ...Refs, typename = no_copy_ctor<Record&, Ref1, Refs...>>
explicit Record(Ref1&& ref, Refs&&... refs)
{ /*...*/ }
模板
显式记录(参考1和参考,参考和…参考)
{ /*...*/ }

问题

调用
Record rec2(rec);
时,有两个可行的构造函数:复制构造函数
Record(Record const&)
和带有
Refs={Record&}
的变量构造函数,其结果是
Record(Record&)
。后者是一个更好的候选人,因为它是一个不太符合简历要求的推荐人,所以它会赢,即使这不是你想要的

解决方案

您希望删除任何应该调用移动或复制构造函数的内容,使其不再是可变构造函数的可行候选。简单地说,如果
Refs…
由一个单一类型组成,该类型要么是对从
记录派生的类型的引用,要么只是一个普通值-我们不希望使用可变构造函数tructor。包含派生实例也很重要,因为您肯定希望
SpecialRecord sr;Record r(sr);
调用复制构造函数

既然出现了这种情况,将其作为类型特征是很有用的。基本情况是,它既不是复制也不是移动:

template <typename T, typename... Ts>
struct is_copy_or_move : std::false_type { };
模板
结构是_copy_或_move:std::false_type{};
我们只需专注于一种类型:

template <typename T, typename U>
struct is_copy_or_move<T, U>
: std::is_base_of<T, std::decay_t<U>>
{ }
模板
结构是复制还是移动
:std::是的基础吗
{ }
然后我们只需要用这个SFINAE的替代品替换我们的变量构造函数:

template <typename... Refs,
          typename = std::enable_if_t<!is_copy_or_move<Record, Refs...>::value>
          >
Record(Refs&&...);
模板
>
记录(参考文献和…);

现在,如果参数是这样的,那么这应该是对复制或移动构造函数的调用,变量构造函数将不再可行。

我无法写出完整的答案,但这应该可以帮助您基本思想是使用SFINAE。@DanielJour这与我的p.p.S.部分有点类似,但thx,我很高兴知道这是已知的问题…对于fu来说为了验证这个问题,应该指出的是,通用引用将正式被称为转发引用。可以找到这方面的建议。是否有任何缺点(使用手动
const_cast
)?那么move-ctr呢?@tower120:删除
const
可能很危险,我在添加
const
时看到的唯一副作用是使用其他重载(如此处所示)。@tower120:可能已经调用了move构造函数,但如果需要,您可以为
const-Record&
添加额外的重载。“顺便说一句,您可能更喜欢使用static_cast来添加常量”-为什么?@tower120:请看,您必须(重新)使用SFINAE解决方案实现默认构造函数。事实上,情况更复杂,您忘记检查
sizeof…(参考文献)==0
@Jarod42您假设OP想要使用变量构造函数作为零参数构造函数。@Jarod42在
Record rec2(rec)
Refs
的大小实际上是零。您能详细说明一下检查它吗?对于大小,我的意思是您也禁止
Record rec2(rec,foo);
template<class T1, class T2, class... Refs>
using no_copy_ctor = typename std::enable_if <
    !std::is_same<T1, T2>::value || sizeof...(Refs)>::type;
template<class Ref1, class ...Refs, typename = no_copy_ctor<Record&, Ref1, Refs...>>
explicit Record(Ref1&& ref, Refs&&... refs)
{ /*...*/ }
template <typename T, typename... Ts>
struct is_copy_or_move : std::false_type { };
template <typename T, typename U>
struct is_copy_or_move<T, U>
: std::is_base_of<T, std::decay_t<U>>
{ }
template <typename... Refs,
          typename = std::enable_if_t<!is_copy_or_move<Record, Refs...>::value>
          >
Record(Refs&&...);