C++将运算符=()赋值转换为构造的具体规则是什么?例如Foo foo = bar
,如果Foo的构造函数接受bar作为参数(如果它存在的话),那么它实际上会调用它。我在谷歌上搜索了一下它是如何工作的,但似乎什么都找不到。
我很难弄清楚为什么下面的赋值试图采用构造函数,但没有采用明显正确的构造函数:HandlePtr(TYPE&resource)。使用实际构造语法进行构造可以很好地工作,但使用赋值运算符则不行。
代码(显然是为了简洁而编辑的):
template< typename TYPE >
class HandlePtr {
public:
HandlePtr( void ) = default;
HandlePtr( HandlePtr< TYPE >& other ) = default;
HandlePtr( TYPE& resource ) {} // generally I would make this explicit, but for testing purposes I took it out
~HandlePtr( void ) = default;
public:
HandlePtr<TYPE>& operator=( TYPE& resource ) { return *this; }
HandlePtr<TYPE>& operator=( HandlePtr<TYPE>& other ) { return *this; }
};
int main ( void ) {
int x = 5;
HandlePtr< int > g( x ); // works
HandlePtr< int > i;i = x; // works
HandlePtr< int > h = x; // doesn't work
// also tried this just out of curiosity:
HandlePtr< int > h = HandlePtr< int >( x ); // also does not work
return 0;
}
错误:
shit.cpp: In function ‘int main()’:
try.cpp:19:24: error: no matching function for call to ‘HandlePtr<int>::HandlePtr(HandlePtr<int>)’
HandlePtr< int > h = x; // doesn't work
^
try.cpp:19:24: note: candidates are:
try.cpp:7:3: note: HandlePtr<TYPE>::HandlePtr(TYPE&) [with TYPE = int]
HandlePtr( TYPE& resource ) {} // generally I would make this explicit, but for testing purposes I took it out
^
try.cpp:7:3: note: no known conversion for argument 1 from ‘HandlePtr<int>’ to ‘int&’
try.cpp:6:3: note: HandlePtr<TYPE>::HandlePtr(HandlePtr<TYPE>&) [with TYPE = int]
HandlePtr( HandlePtr< TYPE >& other ) = default;
^
try.cpp:6:3: note: no known conversion for argument 1 from ‘HandlePtr<int>’ to ‘HandlePtr<int>&’
try.cpp:5:3: note: HandlePtr<TYPE>::HandlePtr() [with TYPE = int]
HandlePtr( void ) = default;
^
try.cpp:5:3: note: candidate expects 0 arguments, 1 provided
try.cpp:20:20: error: redeclaration of ‘HandlePtr<int> h’
HandlePtr< int > h = HandlePtr< int >( x ); // also does not work
^
try.cpp:19:20: error: ‘HandlePtr<int> h’ previously declared here
HandlePtr< int > h = x; // doesn't work
您在声明中忽略了这一点:
T t = u;
这不是赋值运算符。t = u;
不是声明的子表达式。这里唯一的表达式是u
;并且表达式CCD_ 4的评估结果被用作正在声明的对象CCD_。
如果u
具有类型T
,则t
是从u
复制构造的。
如果u
不具有类型T
,则首先需要将u
转换为类型T
。这将创建类型为T
的右值。
您没有任何接受右值的构造函数,因此T t = u;
和相同的T t = T(u);
都会失败。但是,T t(u)
成功了,因为没有创建任何右值;值CCD_ 18被用作构造函数CCD_。
简化代码示例:
struct T
{
T(int &);
T(T&);
T();
T &operator=(int &);
};
int main()
{
int x = 5;
T g(x); // OK, T(int &)
T g2(5); // fail, looks for T(int const &)
T i; // OK, T()
i = x; // OK, T::operator=(int&)
T h3 = i; // OK, T(T&)
T h1 = T(x); // fail, looks for T(T const &)
T h2 = x; // fail, identical to previous line
}
通常应该使用const &
作为复制构造函数和赋值运算符的参数;那么所有这些"失败"的情况都变为"OK",因为右值可以绑定到常量引用。