C ++ 0x完美转发阻碍复制ctor的方式?

时间:2011-06-06 08:30:59

标签: c++11

使用MSVC2010 ......

我有一个包含std :: string的结构,定义了标准的移动ctor,以及一个完美的转发ctor,用于将参数转发给std :: string ctor。

struct Wrapper
{
  std::string value;

  Wrapper()
  {
  }

  Wrapper( Wrapper const& rhs )
    :value(rhs.value)
  {
  }

  Wrapper( Wrapper&& rhs )
    :value(std::move(rhs.value))
  {
  }

  Wrapper& operator=( Wrapper const& rhs )
  {
    value = rhs.value;
    return *this;
  }

  Wrapper& operator=( Wrapper&& rhs )
  {
    value = std::move(rhs.value);
    return *this;
  }


  template<typename StringT>
  Wrapper( StringT&& value )
    :value(std::forward<StringT>(value))
  {
  }
};

但是现在看来我无法从另一个包装器

复制构造一个Wrapper
Wrapper w0;
Wrapper w1(w0);

这导致指向完美转发ctor的编译错误,说它无法将Wrapper转换为std :: string。这是正确的行为吗?编译器是否应该调用copy ctor,而不是模板化的重载?

1>t:\depot\warp\code\apps\pf_test\main.cpp(56): error C2664: 'std::basic_string<_Elem,_Traits,_Ax>::basic_string(const std::basic_string<_Elem,_Traits,_Ax> &)' : cannot convert parameter 1 from 'Wrapper' to 'const std::basic_string<_Elem,_Traits,_Ax> &'
1>          with
1>          [
1>              _Elem=char,
1>              _Traits=std::char_traits<char>,
1>              _Ax=std::allocator<char>
1>          ]
1>          Reason: cannot convert from 'Wrapper' to 'const std::basic_string<_Elem,_Traits,_Ax>'
1>          with
1>          [
1>              _Elem=char,
1>              _Traits=std::char_traits<char>,
1>              _Ax=std::allocator<char>
1>          ]
1>          No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>          t:\depot\warp\code\apps\pf_test\main.cpp(63) : see reference to function template instantiation 'Wrapper::Wrapper<Wrapper&>(StringT)' being compiled
1>          with
1>          [
1>              StringT=Wrapper &
1>          ]
1>

如果我定义另一个复制ctor,一个对Wrapper进行非const引用(如下所示),那么一切似乎都很好......这是前进的方式吗?或者我搞砸了什么?或者这是VS2010中的错误?

  Wrapper( Wrapper& rhs )
    :value(rhs.value)
  {
  }

1 个答案:

答案 0 :(得分:4)

是的,这是正确的行为。

在这种情况下可能会调用两个构造函数 - 复制构造函数和模板构造函数。但是,模板构造函数可能会将类型推断为完全匹配Wrapper(StringT&&)StringT = Wrapper&生成完全匹配Wrapper(Wrapper&)),从而使用而不是复制构造函数。< / p>

建议的解决方法 - 使用std::enable_if中的<type_traits>

template <typename StringT>
Wrapper(StringT&& value,
  typename std::enable_if<
    !std::is_same<
      StringT,
      Wrapper&
    >::value
  >::type* = 0)
  : value(std::forward<StringT>(value))
{ }

看到它正常工作here