Clang (7, 8, trunk) rejects the following code
enum class E {};
inline static constexpr auto e = E{};
// inline static constexpr auto e = nullptr;
template<auto, int> class S;
template<int a, int b> class S<a, b> {};
template<int b> class S<e, b> {};
int main() {
S<0, 0> s;
}
with an error:
error: ambiguous partial specializations of 'S<0, 0>' note: partial specialization matches [with a = 0, b = 0] template<int a, int b> class S<a, b> {}; ^ note: partial specialization matches [with b = 0] template<int b> class S<e, b> {}; ^
Why is it ambiguous? How can e
match 0
? If I replace E{}
with nullptr
, Clang stops complaining. This looks like a Clang's bug. GCC compiles it just fine.
If it is a bug, what is a workaround? In my case, the auto
parameter can be either E
(and only one value E{}
) or int
. Then:
template<auto, int, typename> class S_impl; template<int a, int b> class S_impl<a, b, int> {}; template<int b> class S_impl<e, b, E> {}; template<auto a, int b> using S = S_impl<a, b, decltype(a)>;
Is there a more succinct way?
Clang is doing the deduction wrong. It is similar to this bug , linked to this question (not exactly identical as you are using auto in template parameters which will prevent you to compile using stdc++14).
An interesting case is that it is not the case if it's a complete specialization; only on partial specialization :
#include <iostream>
enum class E {};
inline static constexpr auto e = E{};
template <auto a, int b>
class FOO;
template <int a, int b > class FOO<a, b> {};
template <int b> class FOO<e, b> {};
template <auto a, int b>
class BAR;
template <int a, int b > class BAR<a, b> {};
template <> class BAR<e, 0> {};
template <auto a>
class BAZ;
template <int a> class BAZ<a> {};
template <> class BAZ<e> {};
int main() {
// FOO <0, 0> foo; // <= Not Ok
BAR<0, 0> bar; // <= Ok
BAZ<0> baz; // <= Ok
}
Any solution that force the deduction of the type template parameter will work therefore your suggested solution is perfectly valid. IMHO, I would avoid using auto in template parameter when not necessary to improve readability :
template <typename T, T value, int> class S_impl; // <= this auto is not necessary
template <int a, int b> class S_impl<int, a, b> {};
template <int b> class S_impl<E, e, b> {};
// Either define S to use S<0,0> or directly use S_impl<int, 0, 0>
template <auto a, int b> using S = S_impl<decltype(a), a, b> // <= this auto is necessary
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.