yur*_*hek 5 c++ templates partial-specialization language-lawyer c++17
考虑:
#include <type_traits>
template <typename>
struct Tag {};
template <typename T>
auto tag = Tag<T>{};
template <typename...>
struct SelectorImpl;
// 1
template <auto... xs>
struct SelectorImpl<std::integral_constant<decltype(xs), xs>...>
{};
// 2
template <typename T, Tag<T>* tag, auto... xs>
struct SelectorImpl<std::integral_constant<decltype(tag), tag>,
std::integral_constant<decltype(xs), xs>...>
{};
template <auto... params>
struct Selector
: SelectorImpl<std::integral_constant<decltype(params), params>...>
{};
int main() {
Selector<&tag<int>, 1, 2>{};
}
Run Code Online (Sandbox Code Playgroud)
gcc和clang都无法编译它,报告这些特殊化SelectorImpl是不明确的.我相信专业化#2更专业.我错了吗?难道同样的问题,因为在这里?这是一个错误吗?
First of all, I wanted to be sure that <char X> has 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");
Run Code Online (Sandbox Code Playgroud)
Result: yep, it has precedence (no ambiguity)
Then I applied the same example with variadic args: 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
Run Code Online (Sandbox Code Playgroud)
Looks like template<char v, auto... x> doesn't have precedence over template<auto... x>.
If we remove the std::integral_constant, it works properly: https://godbolt.org/g/grRC8h
This confirms the bug :)
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
Run Code Online (Sandbox Code Playgroud)