如何解决使用std :: enable :: if和std :: is_base_of约束继承
鉴于以下情况:
class A {};
class B : public A {};
class C : public A {};
class D : public A {};
template<typename T/*std::enable_if and std::is_base_of here*/> class X {};
当我声明X时
然后我想约束typename T
强制性地成为A的子类,否则我会得到编译错误。
int main()
{
X<B> x1 = {}; //should work;
X<C> x2 = {}; //should work;
X<D> x2 = {}; //should work;
X<std::string> = {}; //should generate a compiling error;
X<int> = {}; //should generate a compiling error;
};
解决方法
或者,static_assert
可能就足够了:
template<typename T>
class X {
static_assert(std::is_base_of<A,T>::value,"!");
};
,
使用enable_if
的正确语法是
template<typename T,std::enable_if_t<std::is_base_of_v<A,T>,bool> = true>
class X {};
现在,如果A
是T
的基数,则std::is_base_of_v<A,T>
是true
,而std::enable_if_t
变成bool
,我们将其赋值true
中的。如果A
不是T
的基数,则条件为false,并且std::enable_if_t
无结果,并且该模板将作为可行的候选者被丢弃,并且会生成编译器错误。
第三个也是同样的常见变体
-
static_assert
来自Jarod42:s answer,并且 - 使用
std::enable_if_t
作为非类型模板参数的类型,默认为NathanOliver's answer中的某个值(template<...,std::enable_if_t<...,bool> = true>
)
是将std::enable_if_t
用作类型模板参数的默认模板参数(与非类型模板参数的类型相比):
template<typename T,typename = std::enable_if_t<std::is_base_of_v<A,T>>>
class X {};
这比使用非类型模板参数方法要简短一些。
但是它有一个缺点,那就是当用于函数模板时,它不能与SFINAE结合使用,例如仅基于谓词的相反结果来重载两个变体:
// Not OK.
template<typename T,T>>>
void foo(const T&) { /* some impl */ }
// Error: re-definition of foo
template<typename T,typename = std::enable_if_t<!std::is_base_of_v<A,T>>>
void foo(const T&) { /* another impl */ }
由于这两个重载仅在其默认模板参数(这不是功能模板的签名的一部分)上有所不同,因此它们声明具有相同签名的两个不同的功能模板,这是非法的。
如果我们改为使用非类型模板方法,则这不是问题:
// OK
template<typename T,T>>* = nullptr>
void foo(const T&) { /* some impl */ }
template<typename T,std::enable_if_t<!std::is_base_of_v<A,T>>* = nullptr>
void foo(const T&) { /* another impl */ }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。