自动非类型模板参数:Clang 中不明确的偏特化
Auto non-type template parameter: ambiguous partial specializations in Clang
Clang (7, 8, trunk) 拒绝以下代码
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;
}
出现错误:
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> {};
^
为什么会模棱两可? e
如何匹配0
?如果我将 E{}
替换为 nullptr
,Clang 将停止抱怨。这看起来像 Clang 的错误。 GCC 编译它就好了。
如果是错误,有什么解决方法?在我的例子中,auto
参数可以是 E
(并且只有一个值 E{}
)或 int
。那么:
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)>;
有没有更简洁的方法?
Clang 推导错误。它类似于 this bug, linked to this (与您在模板参数中使用 auto 不完全相同,这将阻止您使用 stdc++14 进行编译)。
一个有趣的案例是,如果是完全专精就不是这样;仅部分专业化:
#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
}
任何强制推导类型模板参数的解决方案都可以使用,因此您建议的解决方案完全有效。恕我直言,为了提高可读性,我会避免在模板参数中使用 auto :
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
Clang (7, 8, trunk) 拒绝以下代码
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;
}
出现错误:
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> {}; ^
为什么会模棱两可?
e
如何匹配0
?如果我将E{}
替换为nullptr
,Clang 将停止抱怨。这看起来像 Clang 的错误。 GCC 编译它就好了。如果是错误,有什么解决方法?在我的例子中,
auto
参数可以是E
(并且只有一个值E{}
)或int
。那么: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)>;
有没有更简洁的方法?
Clang 推导错误。它类似于 this bug, linked to this
一个有趣的案例是,如果是完全专精就不是这样;仅部分专业化:
#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
}
任何强制推导类型模板参数的解决方案都可以使用,因此您建议的解决方案完全有效。恕我直言,为了提高可读性,我会避免在模板参数中使用 auto :
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