У меня есть следующий код, который создает один объект t2 с помощью явного конструктора преобразования, который выполняет неявное преобразование t1. Это ожидается и описано в языке программирования C ++, в разделе 11.4.1 третьего издания.
#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’, все же это даже показывает оператор-кандидат функция string () {
Что дает? И что стандарт C ++ говорит о неявных преобразованиях в конструкторах инициализации? я предполагать что это должно учитываться как два неявных преобразования и, следовательно, не допускается, но вывод компилятора вовсе не предполагает этого.
Во-первых, неправильно звонить test2::test2(string)
«конструктор явного преобразования». Он будет использоваться в неявных преобразованиях (отметьте его explicit
если ты не хочешь этого).
Во всяком случае, сообщение об ошибке Clang на месте, и он почти идеально объясняет, что происходит.
Это:
test2 t2(t1);
называется прямая инициализация. Все конструкторы для test2
являются кандидатами и, кроме того, компилятор может запустить последовательность неявных преобразований в соответствии с аргументами. Находит test1::operator string
а также test2::test(string)
и все хорошо.
Это:
test2 t2 = t1;
называется инициализация копии. Выражение справа от =
должен быть преобразован в test2
и тогда для конструирования объекта будет вызван либо конструктор копирования, либо перемещение (по крайней мере, теоретически он может быть позднее исключен как оптимизация, но, тем не менее, он должен быть доступен).
Других решений пока нет …