Приведенный ниже код компилируется в clang (я пробовал 7 и 8), но не в gcc (7, 8 или 9), все с использованием --std=c++17
.С gcc я получаю ошибку ambiguous template instantiation
, как вы можете видеть здесь: https://godbolt.org/z/69Bomq.
Я могу исправить это для gcc, раскомментировав #define FIX_GCC
.Если я изменяю first_type<C>
и first_type<const C>
на C
и const C
в специализациях traits<Map<...>>
, он также компилируется, но в моем реальном коде, если есть некоторые enable_if_t<...>
, чтобы сузить специализацию там.
GCC здесь не так?Или я делаю что-то не так, что clang может принять?
Обновление: Удаление одного слоя шаблонов, т.е. Map
, в специализации также делает GCC счастливым даже с псевдонимом шаблонаfirst_type
, см. https://godbolt.org/z/90kGEP.
<source>: In function 'int main()':
<source>:36:38: error: ambiguous template instantiation for 'struct traits<Map<const Foo> >'
36 | std::cout << traits<Map<const Foo>>::N << std::endl;
| ^~
<source>:24:8: note: candidates are: 'template<class C> struct traits<Map<first_type<C> > > [with C = const Foo]'
24 | struct traits<Map<first_type<C>>> {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:30:8: note: 'template<class C> struct traits<Map<first_type<const C> > > [with C = Foo]'
30 | struct traits<Map<first_type<const C>>> {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:36:40: error: incomplete type 'traits<Map<const Foo> >' used in nested name specifier
36 | std::cout << traits<Map<const Foo>>::N << std::endl;
| ^
#include <iostream>
#include <type_traits>
template <class T, class...>
using first_type = T;
class Foo {};
template <class C>
class Map {};
template <class C>
struct traits {};
//#define FIX_GCC
#ifdef FIX_GCC
template <typename C>
struct traits<Map<first_type<C, std::enable_if_t<!std::is_const_v<C>>>>> {
static constexpr int N = 2;
};
#else
template <typename C>
struct traits<Map<first_type<C>>> {
static constexpr int N = 2;
};
#endif
template <typename C>
struct traits<Map<first_type<const C>>> {
static constexpr int N = 3;
};
int main() {
std::cout << traits<Map<Foo>>::N << std::endl;
std::cout << traits<Map<const Foo>>::N << std::endl;
return 0;
}