我已经熟悉SFINAE,以及如何将其用于基于传递的类型(通过使用std :: enable_if)来启用特定模板。但是,我最近开始在一个项目中进行以下操作:使用SFINAE时,根据提供的枚举VALUE创建类专门化。现在,我知道考虑到我之前做过的事情,可以基于枚举值进行专业化(像这样):
enum Specifier
{
One,
Two,
Three
}
template <Specifier>
class Foo
{
public:
void Bar();
}
template<>
void Foo<Specifier::One>::Bar()
{
}
但是,现在我想使用SFINAEBar()
对多个枚举值使用特定的特殊化。像这样:
template <Specifier Type>
class Foo
{
public:
template <typename std::enable_if<Type == Specifier::Two || Type == Specifier::One, void>::type>
void Bar();
template <typename std::enable_if<Type == Specifier::Three, void>::type>
void Bar();
}
知道这是否可能吗,如果可以,我将如何去做?
从C ++ 17起,您可以使用单个成员函数重载(而不是通过SFINAE出现或不存在的几个重载),其主体在以下情况下利用constexpr:
#include <iostream>
enum class Specifier { One, Two, Three };
template <Specifier S> class Foo {
public:
static constexpr int bar() {
if constexpr ((S == Specifier::One) || (S == Specifier::Two)) {
return 12;
} else if constexpr (S == Specifier::Three) {
return 3;
}
}
};
int main() {
std::cout << Foo<Specifier::One>::bar() << "\n" // 12
<< Foo<Specifier::Two>::bar() << "\n" // 12
<< Foo<Specifier::Three>::bar(); // 3
}
std::enable_if
(_t
)(C ++ 14)同样,您也可以使用SFINAE,要求将非模板成员函数设为带有虚拟模板参数的成员函数模板,因为SFINAE需要在每个函数声明中应用于从属名称,并应用于类模板(类型或(非类型)参数在非模板成员函数的声明中自然不是从属名称:
template <Specifier S> class Foo {
public:
template <Specifier S_ = S,
std::enable_if_t<(S_ == Specifier::One) || (S_ == Specifier::Two)>
* = nullptr>
static constexpr int bar() {
return 12;
}
template <Specifier S_ = S,
std::enable_if_t<(S_ == Specifier::Three)> * = nullptr>
static constexpr int bar() {
return 3;
}
};
请注意,上面的示例使用了std::enable_if_t
C ++ 14中引入的辅助别名模板。如果使用的是C ++ 11,则需要使用typename std::enable_if<..>::type
。
此外,请注意,由于我们必须对成员函数进行模板化,滥用用户可以选择覆盖(虚拟)非类型模板参数的默认模板参数S_
:
Foo<Specifier::One>::bar<Specifier::Three>(); // 3
因此,我们可能希望std::enable_if_t
为每个重载谓词添加一个附加AND条件(S_ == S) && (... predicate as above)
。正如我们将在后面的部分中看到的那样,这在C ++ 20中不再是问题,因为我们可以避免将非模板成员函数仅用作应用SFINAE的模板。
使用专业化而不是重载的替代方法
正如我在以下针对该问题的后续问题的答案中所显示的那样,您还可以在专门化的模板参数列表中(部分专业化的类模板)应用SFINAE:
template <Specifier, typename = void> struct Foo {
static constexpr int bar() { return 1; } // default
};
template <Specifier S>
struct Foo<S,
std::enable_if_t<(S == Specifier::One) || (S == Specifier::Two)>> {
static constexpr int bar() { return 12; }
};
从C ++ 20开始,您可以使用尾随需求子句对每个重载进行互斥约束,从而重载和约束类模板的非模板成员函数:
template <Specifier S> class Foo {
public:
static constexpr int bar() requires((S == Specifier::One) ||
(S == Specifier::Two)) {
return 12;
}
static constexpr int bar() requires(S == Specifier::Three) { return 3; }
};
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句