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++_Templates_C++11_C++14_Move Semantics - Fatal编程技术网

C++ 使用模板将语义从一种类型移动到另一种类型

C++ 使用模板将语义从一种类型移动到另一种类型,c++,templates,c++11,c++14,move-semantics,C++,Templates,C++11,C++14,Move Semantics,是否可能有一个自身带有移动构造函数的结构a和一些可以从其他类型(例如结构B)移动的构造函数,但有一个模板演绎,这样类型B就不会直接硬编码为另一个移动构造函数: struct A{ A()= default; A(A&&a){ /* A's move constructor */ } template<typename T> A(T&&t){ /* (not a move constr

是否可能有一个自身带有移动构造函数的结构a和一些可以从其他类型(例如结构B)移动的构造函数,但有一个模板演绎,这样类型B就不会直接硬编码为另一个移动构造函数:

 struct A{
      A()= default;
      A(A&&a){ /* A's move constructor */ }

      template<typename T>
      A(T&&t){ 
        /* (not a move constructor! by std., matches also lvalues) 

        move from t
        (meta programming to check if we can move the type) 
        */
      } 


}

struct B{};

如何实现这一点?

只需在构造函数中取一个B&&值,就像在构造函数中取a一样。

只需在构造函数中取一个B&&值,就像在构造函数中取a一样。

如果希望构造函数模板接受任意右值,可以在以下情况下使用enable\u:


如果希望构造函数模板接受任意右值,可以在以下情况下使用enable_:


最干净的解决方案是为左值创建更好的构造函数,然后=删除它:

如果您不知道这两个选项中的哪一个是您想要的,那么SFINAE的使用可能只值得这么复杂——也就是说,您从其他地方继承了构造函数


还有最后一个角落案例-AT const&&和AA const&&在某些角落案例中可能会出现。我让它像一个左值向量,因为你不能从一个T常量开始移动&通常。除非T的内脏是可变的,否则我会认为这是个坏主意。

< P>最干净的解决方案是为LValk创建一个更好的构造函数,然后删除它:

如果您不知道这两个选项中的哪一个是您想要的,那么SFINAE的使用可能只值得这么复杂——也就是说,您从其他地方继承了构造函数



还有最后一个角落案例-AT const&&和AA const&&在某些角落案例中可能会出现。我让它像一个左值向量,因为你不能从一个T常量开始移动&通常。除非T的内脏是可变的,否则我会认为这是个坏主意。

注意T&&T是一个转发引用,它允许T推断不同于AB和&B的引用类型。所以这个构造器实际上也会匹配左值。这正是我要如何区分它的问题,但是保持模板推导过程继续进行…?可能有一些sfinae技巧,但我想不出任何东西。这将是另一个问题的主题!你的问题变了。FFS@Gabriel我强烈建议回到原来的问题并单独发布新问题,你所做的只是让人恼火的注意T&&T是一个转发引用,它允许T推断出不同于AB&&b的引用类型。所以这个构造器实际上也会匹配左值。这正是我要如何区分它的问题,但是保持模板推导过程继续进行…?可能有一些sfinae技巧,但我想不出任何东西。这将是另一个问题的主题!你的问题变了。FFS.@Gabriel我强烈建议回到原来的问题并单独发布新问题,你所做的只是让人恼火,所以用这种方式,SFINAE帮助只接受右值:-那是我在寻找默认模板参数的FINAE works吗?typename std::enable_if::value>::type*=nullptr似乎是常用的模式。无论如何,在这两种情况下都会发生编译器错误。但是,使用typename std::enable_if::value>::type*=nullptr生成的错误消息应该更具启发性。@Lingxi是的,SFINAE对模板参数很有效。我更喜欢这个,因为对我来说,它比隐藏在函数参数中更明显;但是你可以用你更喜欢的。例如,Clang为这两者都生成了非常好的消息。如果您真的关心错误消息,您可以添加一个重载,它只接受左值引用,并在其中添加静态断言。与其使用否定检查,为什么不测试std::is_右值_reference::value?太棒了,所以在这种情况下,SFINAE只接受右值是有帮助的:-这是我在寻找默认模板参数的Finae works吗?typename std::enable_if::value>::type*=nullptr似乎是常用的模式。无论如何,在这两种情况下都会发生编译器错误。但是,使用typename std::enable_if::value>::type*=nullptr生成的错误消息应该更具启发性。@Lingxi是的,SFINAE对模板参数很有效。我更喜欢这个,因为对我来说,它比隐藏在函数参数中更明显;但是你可以用你更喜欢的。例如,Clang为这两者都生成了非常好的消息。如果你真的关心错误消息,你可以添加一个重载,只接受左值引用,并在其中添加静态断言。与其使用否定检查,为什么不测试std::is _右值_reference::value?这是另一个解决方案,如果我们想在a中硬编码该类型,是的+1这是另一个解决方案,如果我们想在A中硬编码该类型,是的+1仅仅删除t&构造函数还不够吗?它是否也适用于常数t&?@Yam t const&&将比t&&更好地匹配t&&呢。T const&&有点奇怪,但例如int const foo{return 3;}有一个
常量值返回类型。这是非常奇怪和罕见的,您可能会忽略考虑它,并且在一个大型的、活动的代码库中数年或更长的时间内看不到问题,当您看到它发生时,可能是其他一些代码被梨形化的症状。但更具体的例子是,一个元组作为rvalue:std::getstd::forwardtup传递将是一个int-const&&我认为。@Yakk由于某些原因,foo的类型不是int-const,而是int,因为int是一个基本类型,请参见[expr]/6。但是你的论点适用于类类型。@Yakk-Oops,没有看到第二个-,我以为你在删除t&和const-t&。对不起,@ Dyp C++是一种愚蠢的语言,如果没有,那就是:糟糕的是,在讨论左值、右值和常量时,我永远不应该使用int,除非我想讨论内置类型所包含的异常。就像我做了一个返回数组的函数一样糟糕仅仅删除t&构造函数还不够吗?它是否也适用于常数t&?@Yam t const&&将比t&&更好地匹配t&&呢。T const&&有点奇怪,但例如int const foo{return 3;}有一个const rvalue返回类型。这是非常奇怪和罕见的,您可能会忽略考虑它,并且在一个大型的、活动的代码库中数年或更长的时间内看不到问题,当您看到它发生时,可能是其他一些代码被梨形化的症状。但更具体的例子是,一个元组作为rvalue:std::getstd::forwardtup传递将是一个int-const&&我认为。@Yakk由于某些原因,foo的类型不是int-const,而是int,因为int是一个基本类型,请参见[expr]/6。但是你的论点适用于类类型。@Yakk-Oops,没有看到第二个-,我以为你在删除t&和const-t&。对不起,@ Dyp C++是一种愚蠢的语言,如果没有,那就是:糟糕的是,在讨论左值、右值和常量时,我永远不应该使用int,除非我想讨论内置类型所包含的异常。就像我做了一个返回数组的函数一样糟糕
B b;
A a(std::move(b)); // select the templated constructor (which moves)

A a(b);  // selects the same copy constructor (which moves but we do not want!!
template <
  class T,
  class Sfinae = typename std::enable_if<!std::is_lvalue_reference<T>::value>::type
>
A(T &&t)
template <
  class T,
  class Sfinae = typename std::enable_if<std::is_rvalue_reference<T&&>::value>::type
>
A(T &&t)
struct A{
  A()= default;
  A(A&&a){ /* A's move constructor */ }

  template<class T>
  A(T&&t){ 
  } 
  template<class T>
  A(T const&&)=delete;
  template<class T>
  A(T&t)=delete;
};
struct A{
  A()= default;
  A(A&&a){ /* A's move constructor */ }

  template<class T>
  A(T&&t){ 
    // rvalues end up here
  } 
  template<class T>
  A(T const&&t):A(t) {} // forward to lvalue ctor
  template<class T>
  A(T&t){
    // lvalues end up here
  }
};