21

лязгом и G отличается в поведении на следующий код:Неоднозначности с участием шаблонного оператора преобразования и неявный конструктор копирования

struct foo 
{ 
    foo(int); 
}; 

struct waldo 
{ 
    template <typename T> 
    operator T(); 
}; 

int main() 
{ 
    waldo w; 
    foo f{w}; 
} 

Этого код принимается лязгом, с foo(int) конструктора вызывается. Тем не менее, GCC жалуется неоднозначность между foo(int) конструктора и неявно сгенерированным копированием и перемещением конструкторами:

test.cpp: In function 'int main()': 
test.cpp:15:12: error: call of overloaded 'foo(<brace-enclosed initializer list>)' is ambiguous 
    foo f{w}; 
      ^
test.cpp:15:12: note: candidates are: 
test.cpp:3:5: note: foo::foo(int) 
    foo(int); 
    ^
test.cpp:1:8: note: constexpr foo::foo(const foo&) 
struct foo 
     ^
test.cpp:1:8: note: constexpr foo::foo(foo&&) 

Кто прав?

Также интересно отметить, что если foo f{w} изменен на foo f(w) (обратите внимание на изменение от скобок до скобок), как gcc, так и clang дают ошибку. Это заставляет меня надеяться, что поведение gcc для приведенного выше примера (например, дающее ошибку) является правильным, иначе возникнет странная несогласованность между формами инициализации () и {}.

EDIT: После Kerrek предложение SB «s, я попытался delete ИНГ конструктор копирования из foo:

struct foo 
{ 
    foo(int); 
    foo(const foo&) = delete; 
}; 

поведение остается тем же самым.

+1

Я бы с GCC на этом один: Оба преобразования в 'int' и' Foo' возможны, так что это действительно выглядит неоднозначной , Попробуйте удалить или по умолчанию использовать конструкторы copy/move, и сравнить их. –

+4

Удаленные функции @KerrekSB участвуют в разрешении перегрузки. – TemplateRex

+0

@rhalbersma: Хорошая точка! –

ответ

11

Для инициализации списка, если элемент списка имеет один элемент (здесь w), и рассматривается конструктор класса X с параметром «ссылка на const/volatile X», не учитываются определенные пользователем преобразования. Поэтому нельзя использовать конструктор копирования и перемещения foo. Таким образом, конструктор foo(int) однозначно выбран.

Так что Clang здесь верен.

EDIT: Для людей Стандарты в данном разделе, 13.3.3.1p4

+1

для перекрестных ссылок: http://stackoverflow.com/q/12677711/819272 – TemplateRex

 Смежные вопросы

  • Нет связанных вопросов^_^