Почему оператор преобразования не вызывается при использовании синтаксиса инициализации и почему сообщение об ошибке clang кажется неверным?

StackOverflow https://stackoverflow.com//questions/20008689

Вопрос

У меня есть следующий код, который создает один объект t2 с использованием конструктора явного преобразования, который выполняет неявное преобразование t1.Это ожидаемо и описано в разделе 11.4.1 третьего издания «Язык программирования C++».

#include <iostream>
#include <string>
using namespace std;

class test1 {
public:
    test1() {}
    operator string() {
        cout << "test1 string conversion operator called" << endl;
        return string();
    }
};
class test2 {
public:
    test2() {}
    test2(string s) {
        cout << "test2 string conversion constructor called" << endl;
    }
};

int main() {
    test1 t1;
    test2 t2(t1);
    return 0;
}

И как и следовало ожидать:

> clang++ --version
Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin13.0.2
Thread model: posix
> clang++ -std=c++11 test.cc
> ./a.out
test1 string conversion operator called
test2 string conversion constructor called

Однако при изменении конструкции t2 на синтаксис инициализации:

test1 t1;
test2 t2 = t1;
return 0;

Clang выводит следующее:

test.cc:23:15: error: no viable conversion from 'test1' to 'test2'
        test2 t2 = t1;
              ^    ~~
test.cc:13:11: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'test1' to 'const test2 &' for 1st argument
    class test2 {
          ^
test.cc:13:11: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'test1' to 'test2 &&' for 1st argument
    class test2 {
          ^
test.cc:16:9: note: candidate constructor not viable: no known conversion from 'test1' to 'string' (aka 'basic_string<char, char_traits<char>, allocator<char> >') for 1st argument
        test2(string s) {
        ^
test.cc:8:9: note: candidate function
        operator string() {
        ^
1 error generated.

Я не знаю, должна ли инициализация выполнять такое неявное преобразование, но сообщение об ошибке кажется очень неправильным. неизвестное преобразование из «test1» в «строку», но это даже показывает оператор функции-кандидата string() {

Что дает?А что говорит стандарт C++ о неявных преобразованиях в конструкторах инициализации?я предполагать что это следует считать двумя неявными преобразованиями и, следовательно, не разрешать, но вывод компилятора вообще не предполагает этого.

Это было полезно?

Решение

Во-первых, неправильно звонить test2::test2(string) а «конструктор явного преобразования».Он будет использоваться в неявных преобразованиях (отметьте его explicit если ты этого не хочешь).

В любом случае, сообщение об ошибке clang точное и почти идеально объясняет, что происходит.
Этот:

test2 t2(t1);

называется прямая инициализация.Все конструкторы для test2 являются кандидатами, и, кроме того, компилятор может выполнить последовательность неявных преобразований для соответствия аргументам.Он находит test1::operator string и test2::test(string) и все хорошо.

Этот:

test2 t2 = t1;

называется копирование инициализации.Выражение справа от = необходимо преобразовать в test2 а затем для создания объекта будет вызван либо конструктор копирования, либо конструктор перемещения (по крайней мере, теоретически его позже можно исключить из оптимизации, но, тем не менее, он должен быть доступен).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top