Pergunta

Quais são exatamente as regras para C++ converter uma atribuição de operador=() em uma construção?Como Foo foo = bar na verdade, chamará o construtor de Foo aceitando bar como argumento, se existir.Pesquisei no Google como isso funciona, mas não consigo encontrar nada.

Estou tendo problemas para descobrir por que a tarefa abaixo está tentando usar um construtor, mas não está usando o obviamente correto:HandlePtr( TYPE& recurso ).A construção usando a sintaxe de construção real funciona bem, mas não com o operador de atribuição.

código (obviamente editado por questões de brevidade):

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;
}

erros:

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
Foi útil?

Solução

Você está negligenciando isso no declaração:

T t = u;

este não é o operador de atribuição. t = u; não é uma subexpressão de uma declaração.A única expressão aqui é u;e o resultado da avaliação da expressão u é usado como inicializador para o objeto t sendo declarado.

Se u tem tipo T, então t é construído por cópia a partir de u.

Se u não tem tipo T, então u primeiro precisa ser convertido para o tipo T.Isto cria um valor do tipo T.

Você não tem nenhum construtor que aceite um rvalue, então T t = u;, e o idêntico T t = T(u); ambos falham.No entanto, T t(u) é bem-sucedido porque nenhum valor é criado;O valor que u é usado como argumento para o construtor T(U &).

Exemplo de código simplificado:

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 
}

Normalmente você deve usar const & como parâmetro para construtores de cópia e operadores de atribuição;então, todos esses casos de "falha" tornam-se "OK" , pois um rvalue pode ser vinculado a uma referência const.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top