clang++ терпит неудачу, но g ++ успешно использует приведение к оператору const-unrelated-type в присваивании
Вот короткий пример, который воспроизводит это "нежизнеспособное преобразование" с лимоном для clang, но справедливо для g ++ различий в поведении компилятора.
#include <iostream>
struct A {
int i;
};
#ifndef UNSCREW_CLANG
using cast_type = const A;
#else
using cast_type = A;
#endif
struct B {
operator cast_type () const {
return A{i};
}
int i;
};
int main () {
A a{0};
B b{1};
#ifndef CLANG_WORKAROUND
a = b;
#else
a = b.operator cast_type ();
#endif
std::cout << a.i << std::endl;
return EXIT_SUCCESS;
}
жить у Годболта
g++ (4.9, 5.2) компилирует это молча; тогда как clang++ (3.5, 3.7) компилирует его
если
using cast_type = A;
или же
using cast_type = const A;
// [...]
a = b.operator cast_type ();
используются, но не с дефолтом
using cast_type = const A;
// [...]
a = b;
В этом случае обвиняет clang++ (3.5) a = b
:
testling.c++:25:9: error: no viable conversion from 'B' to 'A'
a = b;
^
testling.c++:3:8: note: candidate constructor (the implicit copy constructor)
not viable:
no known conversion from 'B' to 'const A &' for 1st argument
struct A {
^
testling.c++:3:8: note: candidate constructor (the implicit move constructor)
not viable:
no known conversion from 'B' to 'A &&' for 1st argument
struct A {
^
testling.c++:14:5: note: candidate function
operator cast_type () const {
^
testling.c++:3:8: note: passing argument to parameter here
struct A {
Со ссылкой на стандарт 2011¹: правильно ли clang ++ отклонять код по умолчанию или g ++ правильно его принимать?
Примечание: вопрос не в том, const
классификатор на cast_type
имеет смысл. Речь идет о том, какой компилятор работает в соответствии со стандартами, и только об этом.
¹ 2014 год не должен иметь значения здесь.
РЕДАКТИРОВАТЬ:
Пожалуйста, воздержитесь от повторной пометки этого тегом C++. Сначала я хотел бы узнать, какое поведение соответствует стандарту 2011 года, и сохранить приверженность комитетов. not to break existing (< 2011) code
из анзаца пока.
1 ответ
Похоже, что это покрыто этим сообщением об ошибке clang. Перегрузка по значению скрывает const lvalue? который имеет следующий пример:
struct A{};
struct B{operator const A()const;};
void f(A const&);
#ifdef ERR
void f(A&&);
#endif
int main(){
B a;
f(a);
}
которая завершается с той же ошибкой, что и код OP. Ричард Смит под конец говорит:
Обновление: мы правильно выбрали 'f(A&&)', но мы ошибаемся, чтобы отклонить инициализацию параметра. Далее уменьшается:
struct A {}; struct B { operator const A(); } b; A &&a = b;
Здесь [dcl.init.ref]p5 bullet 2 bullet 1 bullet 2 не применяется, потому что [over.match.ref]p1 не находит подходящих функций преобразования, потому что "A" не совместим со ссылками с "const A". Таким образом, мы попадаем в [dcl.init.ref]p5 bullet 2 bullet 2, копируем-инициализируем временный тип A из 'b' и привязываем ссылку на него. Я не уверен, где в этом процессе мы пойдем не так.
но затем возвращается с другим комментарием из-за сообщения об ошибке 1604:
DR1604 изменил правила так, чтобы
A &&a = b;
сейчас плохо сформирован. Так что теперь мы правы, чтобы отклонить инициализацию. Но это все еще ужасный ответ; Я снова подтолкнул CWG. Вероятно, нам следует отказаться от f (A &&) во время разрешения перегрузки.
Таким образом, кажется, что технически Clang делает правильные вещи на основе стандартного языка сегодня, но это может измениться, так как, по-видимому, есть несогласие, по крайней мере, с командой Clang, что это правильный результат. Предположительно, это приведет к появлению отчета о дефектах, и нам придется подождать, пока он будет решен, прежде чем мы сможем прийти к окончательному выводу.
Обновить
Похоже, дефектный отчет 2077 был подан на основании этой проблемы.