C ++ с использованием copy-ctor при использовании operator = () — как именно это работает?

Какие именно правила для C ++ преобразуют присваивание operator = () в конструкцию? Такие как Foo foo = bar фактически вызовет конструктор Foo, принимающий bar в качестве аргумента, если он существует. Я гуглил, как это работает, но не могу ничего найти.

У меня проблема с выяснением, почему нижеприведенное назначение пытается взять конструктор, но не принимает явно правильный: HandlePtr (TYPE& ресурс). Конструкция с использованием фактического синтаксиса конструкции работает нормально, но не с оператором присваивания.

код (очевидно, отредактированный для краткости):

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

0

Решение

Вы пропускаете это в декларация:

T t = u;

это не оператор присваивания. t = u; не является подвыражением объявления. Единственное выражение здесь u; и результат оценки выражения u используется как инициализатор для объекта t быть объявленным

Если u имеет тип T, затем t построен из u,

Если u не имеет типа T, затем u сначала нужно преобразовать в тип T, Это создает Rvalue типа T,

У вас нет конструкторов, которые принимают значение, поэтому T t = u;и идентичный T t = T(u); оба терпят неудачу. Тем не мение, T t(u) успешно, потому что не создано значение r; Значение u используется в качестве аргумента для конструктора T(U &),

Пример упрощенного кода:

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 & в качестве параметра для конструкторов копирования и операторов присваивания; тогда все эти «неудачные» случаи становятся «ОК», так как значение может быть связано с константной ссылкой.

2

Другие решения

Других решений пока нет …