Clang 6, clang 7 и gcc 7.1, 7.2 и 7.3 все согласны с тем, что следующее является допустимым кодом С++ 17, но неоднозначно в С++ 14 и С++ 11. MSVC 2015 и 2017 также принимают это. Однако gcc-8.1 и 8.2 отклоняют его даже в режиме С++ 17:
struct Foo
{
explicit Foo(int ptr);
};
template<class T>
struct Bar
{
operator T() const;
template<typename T2>
explicit operator T2() const;
};
Foo foo(Bar<char> x)
{
return (Foo)x;
}
Компиляторы, которые принимают его, выбирают шаблонную явную функцию преобразования Bar::operator T2()
.
Компиляторы, которые отвергают это, соглашаются, что между:
- функция явного преобразования Bar :: operator int()
- сначала используется неявное пользовательское преобразование из
Bar<char>
вchar
, затем неявное встроенное преобразование изchar
вint
, а затем явный конструктор Foo (int).
Итак, какой компилятор прав? В чем разница между стандартом С++ 14 и С++ 17?
Приложение: актуальные сообщения об ошибках
Здесь ошибка для gcc-8.2 -std=c++17
. gcc-7.2 -std=c++14
печатает ту же ошибку:
<source>: In function 'Foo foo(Bar<char>)':
<source>:17:17: error: call of overloaded 'Foo(Bar<char>&)' is ambiguous
return (Foo)x;
^
<source>:3:14: note: candidate: 'Foo::Foo(int)'
explicit Foo(int ptr);
^~~
<source>:1:8: note: candidate: 'constexpr Foo::Foo(const Foo&)'
struct Foo
^~~
<source>:1:8: note: candidate: 'constexpr Foo::Foo(Foo&&)'
И здесь ошибка от clang-7 -std=c++14
(clang-7 -std=c++17
принимает код):
<source>:17:12: error: ambiguous conversion for C-style cast from 'Bar<char>' to 'Foo'
return (Foo)x;
^~~~~~
<source>:1:8: note: candidate constructor (the implicit move constructor)
struct Foo
^
<source>:1:8: note: candidate constructor (the implicit copy constructor)
<source>:3:14: note: candidate constructor
explicit Foo(int ptr);
^
1 error generated.