First of all, I wanted to make sure that <char X> takes precedence over <auto X> . So I wrote this simple test: https://godbolt.org/g/Hy6NVB
template<auto...> struct TestSingleImpl; // 1 template<auto x> struct TestSingleImpl<x> { static constexpr bool value = false; }; // 2 template<char x> struct TestSingleImpl<x> { static constexpr bool value = true; }; static_assert(TestSingleImpl<1234>::value == false, "1"); static_assert(TestSingleImpl<'a'>::value == true, "2");
Result: yep, takes precedence (no ambiguity)
Then I applied the same example with args variables: https://godbolt.org/g/7mWaeH
template <typename...> struct Test; // 1 template<auto v, auto... x> struct Test<std::integral_constant<decltype(v), v>, std::integral_constant<decltype(x), x>...> { static constexpr bool value = true; }; // 2 template<char v, auto... x> struct Test<std::integral_constant<char, v>, std::integral_constant<decltype(x), x>...> { static constexpr bool value = false; }; template <auto... params> struct Selector : Test<std::integral_constant<decltype(params), params>...> {}; static_assert(Selector<1234, 1, 2>::value == true, "1"); // 1 - ok static_assert(Selector<'a', 1, 2>::value == false, "2"); // 2 - AMBIGUITY
Looks like template<char v, auto... x> has no priority over template<auto... x> .
it looks like a HUGE bug in CLANG and GCC
If we remove std::integral_constant , it works correctly: https://godbolt.org/g/grRC8h
This confirms the error :)
template <auto...> struct Test; // 1 template<auto v, auto... x> struct Test<v, x...> { static constexpr bool value = true; }; // 2 template<char v, auto... x> struct Test<v, x...> { static constexpr bool value = false; }; static_assert(Test<1234, 1, 2>::value == true, "1"); // 1 - ok static_assert(Test<'a', 1, 2>::value == false, "2"); // 2 - ok