我之前问了一个问题,为什么std::enable_if<false>
不能在SFINAE上下文中使用,例如:
template <typename T, typename DEFAULTVOID = void>
struct TemplatedStruct {};
template <typename T>
struct TemplatedStruct<T, std::enable_if_t<false>> {}; // enable_if expression
// isn't dependent on template type, is always false and so is an error
但是,在以下示例中,它依赖于模板参数,但这也会创建一个错误:
#include <type_traits>
template <typename value_t_arg>
struct underlyingtype
{
static inline constexpr bool bIsIntegralType =
std::is_integral_v<value_t_arg>;
template <typename T, typename DEFAULTVOID = void>
struct IsSpecialType {
static inline constexpr bool bIsSpecialType = false;
};
template <typename T>
struct IsSpecialType<T, std::enable_if_t<bIsIntegralType>> {
static inline constexpr bool bIsSpecialType = true;
};
// This also creates an error, this is essentially the same as above
template <typename T>
struct IsSpecialType<T, std::enable_if_t<std::is_integral_v<value_t_arg>>> {
static inline constexpr bool bIsSpecialType = true;
};
};
int main()
{
underlyingtype<int> g1; // Works
underlyingtype<double> g2; // std::enable_if_t<false, void>:
// Failed to specialize alias template
}
在第一种情况下,std::enable_if_t<false>
无论我实例化什么,它都无法编译。然而,在另一种情况下,underlyingtype<int> g1;
工作,而当我用双精度实例化它时,它无法编译,这让我认为它们是两个不同的问题。
编辑:我应该提到,这无法使用Visual Studio Community 2019 16.9.3进行编译。
// Failed to specialize alias template
首先,您的代码中没有别名模板。 你只是在关心bIsIntegralType
与std::is_integral_v<value_t_arg>
完全相同的东西,一旦发生underlyingtype
的实例化,它就会被固定(false
或true
)。
因此,这两个专业
template <typename T>
struct IsSpecialType<T, std::enable_if_t<bIsIntegralType>> {
static inline constexpr bool bIsSpecialType = true;
};
// This also creates an error, this is essentially the same as above
template <typename T>
struct IsSpecialType<T, std::enable_if_t<std::is_integral_v<value_t_arg>>> {
static inline constexpr bool bIsSpecialType = true;
};
是一回事,因此叮当说
Class template partial specialization 'IsSpecialType<T>' cannot be redeclared
这与你传递给underlyingtype
value_t_arg
无关。
当删除两个相同的专用化中的任何一个时,代码在underlyingtype<int> g1;
方面是可以的,但是在尝试实例化underlyingtype<double>
时它仍然无效,因为在这种情况下value_t_arg
被"阻止"到double
,这使得bIsIntegralType
只是一个false
编译时值,这反过来意味着你正在传递一个永远和永远的false
给std::enable_if_v
。
换句话说,当你要求underlyingtype<double>
时,编译器开始用value_t_arg = double
underlyingtype
实例化类;此时编译器甚至没有看过IsSpecialType
,但它知道bIsIntegralType == false
,这使得IsSpecialType
的特化代码在上一个问题中无效。
(¹) 别名模板是模板化类型别名,
template <typename T>
using new_name = old_name<T>;
而在您的代码中根本没有using
,因此不可能有类型别名,更不用说别名模板了。
基于这个和上一个问题,看起来你正在尝试进入SFINAE和模板元编程。如果我可以给你一个建议,学习它的一个好方法是阅读并理解Boost.Hana库是如何工作的。那里有很多TMP和SFINAE,但是代码的质量很高(恕我直言),并且代码本身的文档非常好,因此可以理解(显然需要时间)。
考虑这一行:
std::cout << underlyingtype<double>::IsSpecialType<char>::bIsSpecialType << "n";
我们应该如何解释它?
underlyingtype
是一个模板。underlyingtype<double>
不是模板,它是一种类型,underlyingtype
的特定实例化。underlyingtype<double>::IsSpecialType
是一个模板,是(非模板)类类型的成员underlyingtype<double>
此模板具有单个参数 T。underlyingtype<double>::IsSpecialType<char>
是上述模板的实例化。
现在,在实例化模板时,其参数将替换为实际参数。未能执行此类替换不是错误。在underlyingtype<double>::IsSpecialType
的情况下,参数为T
。然而std::enable_if_t<std::is_integral_v<value_t_arg>>>
不依赖于T
,所以不会发生替换。