enable_if class 参数不是 void 的模板特化
enable_if for class template specialization with argument other than void
我知道 C++ 编译器优先选择模板特化而不是主模板:
template<class T, class Enable = void>
class A {}; // primary template
template<class T>
class A<T, std::enable_if_t<std::is_floating_point_v<T>, void>> {
}; // specialization for floating point types
但是,我不明白为什么当 void
以外的类型用作 enable_if
的参数时选择失败:
template<class T>
class A<T, std::enable_if_t<std::is_floating_point_v<T>, int>> {
}; // specialization for floating point types
编译器肯定会“看到”class A<T, int>
。
所以肯定不可能是SFINAE,不过主模板比专业模板更受欢迎。
这个问题源于可以使用自定义类型检测机制而不是 enable_if
的上下文,例如SFINAE 友好型提取器,如 common_type
.
当你有
A<some_floating_point_type> some_name;
模板参数为some_floating_point_type
和隐式void
。当编译器实例化时
template<class T>
class A<T, std::enable_if_t<std::is_floating_point_v<T>, int>> {
}; // specialization for floating point types
它会得到 A<some_floating_point_type, int>
,这与 some_name
的 A<some_floating_point_type, void>
类型不匹配。因此,专业化将被忽略,您将获得主模板。您可以通过尝试创建一个 A<some_floating_point_type, int>
来验证这一点,您将看到专业化已被选中。
我发现将专业化视为替代方案很有帮助。首先推导模板参数,然后如果它们匹配任何特化,然后我们切换到使用该替代配方。如果没有,则使用原始配方。
在编译器知道它将用于 primary 模板的类型之前,特化是无关紧要的。
当你写 A<double>
时,编译器只会查看主模板并发现你实际上是指 A<double,void>
。
只有 然后 它正在寻找专业化。现在,如果你的专业是 A<double,int>
,那么它就不适合了,因为你要求的是 A<double,void>
.
简单来说,这
template<class T, class Enable = void>
class A {};
表示“A 是一个模板,它有两个参数,第二个参数默认为 void
”。那是主要模板。当您显式仅提供一个参数时,第二个参数为 void
.
现在专精:
template<class T>
class A<T, std::enable_if_t<std::is_floating_point_v<T>, int>> {
};
这不会改变以上内容。 A
仍然是一个有两个参数的模板,如果没有指定第二个参数,那么它就是 void
。简而言之,当条件为 false
时,它意味着“在 std::enable_if_t<std::is_floating_point_v<T>
中替换 T
是失败的,因为类型别名不存在”,SFINAE 启动并忽略专业化。当条件为 true
时:“每当使用参数 T(某种类型)和 int
实例化 A 时,然后使用此定义”。
当您实例化 A<int>
时,第二个模板参数是 void
。专业化不会改变这一点。即 A<int>
实际上是 A<int,void>
。与专业化不符。
我知道 C++ 编译器优先选择模板特化而不是主模板:
template<class T, class Enable = void>
class A {}; // primary template
template<class T>
class A<T, std::enable_if_t<std::is_floating_point_v<T>, void>> {
}; // specialization for floating point types
但是,我不明白为什么当 void
以外的类型用作 enable_if
的参数时选择失败:
template<class T>
class A<T, std::enable_if_t<std::is_floating_point_v<T>, int>> {
}; // specialization for floating point types
编译器肯定会“看到”class A<T, int>
。
所以肯定不可能是SFINAE,不过主模板比专业模板更受欢迎。
这个问题源于可以使用自定义类型检测机制而不是 enable_if
的上下文,例如SFINAE 友好型提取器,如 common_type
.
当你有
A<some_floating_point_type> some_name;
模板参数为some_floating_point_type
和隐式void
。当编译器实例化时
template<class T>
class A<T, std::enable_if_t<std::is_floating_point_v<T>, int>> {
}; // specialization for floating point types
它会得到 A<some_floating_point_type, int>
,这与 some_name
的 A<some_floating_point_type, void>
类型不匹配。因此,专业化将被忽略,您将获得主模板。您可以通过尝试创建一个 A<some_floating_point_type, int>
来验证这一点,您将看到专业化已被选中。
我发现将专业化视为替代方案很有帮助。首先推导模板参数,然后如果它们匹配任何特化,然后我们切换到使用该替代配方。如果没有,则使用原始配方。
在编译器知道它将用于 primary 模板的类型之前,特化是无关紧要的。
当你写 A<double>
时,编译器只会查看主模板并发现你实际上是指 A<double,void>
。
只有 然后 它正在寻找专业化。现在,如果你的专业是 A<double,int>
,那么它就不适合了,因为你要求的是 A<double,void>
.
简单来说,这
template<class T, class Enable = void>
class A {};
表示“A 是一个模板,它有两个参数,第二个参数默认为 void
”。那是主要模板。当您显式仅提供一个参数时,第二个参数为 void
.
现在专精:
template<class T>
class A<T, std::enable_if_t<std::is_floating_point_v<T>, int>> {
};
这不会改变以上内容。 A
仍然是一个有两个参数的模板,如果没有指定第二个参数,那么它就是 void
。简而言之,当条件为 false
时,它意味着“在 std::enable_if_t<std::is_floating_point_v<T>
中替换 T
是失败的,因为类型别名不存在”,SFINAE 启动并忽略专业化。当条件为 true
时:“每当使用参数 T(某种类型)和 int
实例化 A 时,然后使用此定义”。
当您实例化 A<int>
时,第二个模板参数是 void
。专业化不会改变这一点。即 A<int>
实际上是 A<int,void>
。与专业化不符。