Подтвердить что ты не робот

Это ошибка clang или что-то, что я не знаю о С++?

Рассматривая этот вопрос, я пробовал это с clang и попал в странную ситуацию. Следующий пример:

#include <string>

class ACP
{
public:
    ACP() {}
    operator const std::string() const  { return std::string(); }
    // operator std::string() const  { return std::string(); } <-- makes clang happy
};

void test()
{
   const ACP acp;
   auto a = (std::string)acp;
}

компилируется в coliru с gcc, но с clang не работает. По крайней мере, я не вижу проблемы с этим примером - это ошибка в clang или есть правило, которое фактически объясняет ошибку clang и gcc не так?

Ошибка от clang можно увидеть ниже:

clang -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp:13:26: error: no viable conversion from 'const ACP' to 'std::__cxx11::basic_string<char>'
   auto a = (std::string)acp;
                         ^~~
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.1.0/../../../../include/c++/7.1.0/bits/basic_string.h:421:7: note: candidate constructor not viable: no known conversion from 'const ACP' to 'const std::__cxx11::basic_string<char> &' for 1st argument
      basic_string(const basic_string& __str)
      ^
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.1.0/../../../../include/c++/7.1.0/bits/basic_string.h:493:7: note: candidate constructor not viable: no known conversion from 'const ACP' to 'const char *' for 1st argument
      basic_string(const _CharT* __s, const _Alloc& __a = _Alloc())
      ^
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.1.0/../../../../include/c++/7.1.0/bits/basic_string.h:515:7: note: candidate constructor not viable: no known conversion from 'const ACP' to 'std::__cxx11::basic_string<char> &&' for 1st argument
      basic_string(basic_string&& __str) noexcept
      ^
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.1.0/../../../../include/c++/7.1.0/bits/basic_string.h:542:7: note: candidate constructor not viable: no known conversion from 'const ACP' to 'initializer_list<char>' for 1st argument
      basic_string(initializer_list<_CharT> __l, const _Alloc& __a = _Alloc())
      ^
main.cpp:7:5: note: candidate function
    operator const std::string() const  { return std::string(); }
    ^
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.1.0/../../../../include/c++/7.1.0/bits/basic_string.h:515:35: note: passing argument to parameter '__str' here
      basic_string(basic_string&& __str) noexcept
                                  ^
1 error generated.

Однако я не могу понять, почему компилятор не мог использовать копию ctor из std::string.

4b9b3361

Ответ 1

Упрощенная:

struct A {};
struct B { operator const A(); };
B b;
A a(b);

Это direct-initialization с тип класса типа назначения A, поэтому конструкторы-кандидаты из A перечислены, выбирая все конструкторы A (включая неявно определенные экземпляры копирования и перемещения) и сравнивается разрешение перегрузки для прямая инициализация объекта класса. Сначала конструкторы оцениваются для жизнеспособности, что означает попытку построить неявное преобразование последовательность от b (lvalue b) к их параметру. Поскольку параметр является ссылкой (A const& или A&&), мы должны выполнить инициализацию ссылок. Мы можем инициализировать ссылку A const& от b, так как b можно преобразовать в rvalue A const и A const ( тип целевой ссылки) и A const (тип возврата целевой функции) reference-compatible (так как они одинаковые cv -квалифицированный тип); действительно, это прямая привязка ссылок. Мы не можем инициализировать ссылку A&& из b, так как A&& имеет меньшую cv-квалификацию, чем A const. Таким образом, A::A(A const&) является единственным жизнеспособным конструктором и выбран.

Сообщается о том, что clang несколько раз 1 2 3, но, к сожалению, не был поднят.

Все остальные основные компиляторы (gcc, ICC, MSVC) правильно компилируют код.

Интересно, что, как обсуждалось здесь, clang правильно компилирует код в режиме С++ 03. Если мы заставим A быть типа "С++ 03", подавив его конструктор перемещения, clang скомпилирует полученный код:

struct A { A(A const&) = default; };
struct B { operator const A(); };
B b;
A a(b);

Это указывает на то, что, возможно, clang запутывается конструктором перемещения. Он не должен, поскольку конструктор перемещения не является жизнеспособным; A&& a = b; недействителен.