Ped*_*lló 3 c++ templates template-meta-programming
我有一个模板类,它使用模板参数 ( std::enable_if_t) 来限制主模板参数,如下所示:
template <typename T, typename
= std::enable_if_t<std::is_arithmetic_v<T>>>
class Foo
{
void foo();
}
template<typename T>
void Foo<T>::foo() {} // compiler complains
Run Code Online (Sandbox Code Playgroud)
我知道我可以使用 来解决这个问题static_assert,但我想知道在这种情况下正确的方法是什么。
我想我可以简单地再次复制两个模板参数,但这对我来说似乎很奇怪。
您必须添加第二个模板参数:
// ..................vvvvvvvvvv
template<typename T, typename U>
void Foo<T, U>::foo() {} // compiler doesn't complains anymore
// ........^^
Run Code Online (Sandbox Code Playgroud)
或者,也许更好,在类中实现该方法:
template <typename T, typename
= std::enable_if_t<std::is_arithmetic_v<T>>>
class Foo
{
void foo() {}
// .......^^^
};
Run Code Online (Sandbox Code Playgroud)
无论如何...考虑到您使用 SFINAE 限制(第一个)参数类型的方法有一个缺陷:您正在对第二个模板参数的默认值进行操作,因此可以通过显式包含第二个来绕过它实例化中的模板参数。
T我的意思是......你可以在算术时正确定义类型:
Foo<int> f; // compile
Run Code Online (Sandbox Code Playgroud)
T当不是算术时,不能正确编译:
Foo<void> f; // compilation error
Run Code Online (Sandbox Code Playgroud)
但是,T当您显式包含第二个模板参数时,它会编译(当不是算术时):
Foo<void, void> f; // compiles!!!
Run Code Online (Sandbox Code Playgroud)
我想你不会Foo<void, void>编译它。
为了避免这个问题,可以在等号左边使用SFINAE,删除模板参数,而不是默认值。
例如,你可以写:
template <typename T,
std::enable_if_t<std::is_arithmetic_v<T>, bool> = true>
class Foo
{
void foo() {}
};
Run Code Online (Sandbox Code Playgroud)
这样,Foo当第一个模板参数不是算术类型时,您可以确定没有人可以实例化对象。
这个解决方案有一个小问题(或者可能没有……取决于您的期望):您可以在同一T参数上定义两个不同的类。
我的意思是......你可以定义:
Foo<int> f0;
Foo<int, true> f1; // same type as f0
Foo<int, false> f2; // different type from f0 and f1
Run Code Online (Sandbox Code Playgroud)
为了避免这种情况,对于第二个参数的类型,您可以使用接受单个值的类型。例如:std::nullptr_t
template <typename T,
std::enable_if_t<std::is_arithmetic_v<T>, std::nullptr_t> = nullptr>
class Foo
{
void foo() {}
};
Run Code Online (Sandbox Code Playgroud)
现在,您可以拥有Foo<int>, ,它是 的简写Foo<int, nullptr>,但不能是第二个模板参数不同的类。