使用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))
{
}
};
但是现在看来我无法从另一个包装器
复制构造一个WrapperWrapper 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)
{
}
答案 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。