在C ++中,假设我有一些类mom
。我知道我可以创建一个接受任何类的模板函数,例如:
template <class T> void Iacceptanything(T x)
{
// Do something
}
现在,这很好用,但是我想创建一个更加限制的模板类,它接受T
任何继承自类mom
的类型。我想让函数接受mom
作为唯一的参数类型,但在该函数中我需要用参数构建一个模板对象,因此我需要保留它的类型(即,我的对象不应该是“被修剪”只是它是mom
)的继承人。
我需要的是:
template <class T:mom> void Iacceptonlysonsofmom(T x)
{
// Do something
}
这有可能吗?
答案 0 :(得分:4)
使用std::enable_if
和std::is_base_of
。
#include <type_traits>
#include <iostream>
class Base { };
class Derived : public Base { };
class NotDerived { };
// If the return type of foo() is not void, add where indicated.
template <typename T>
typename std::enable_if<std::is_base_of<Base, T>::value /*, some_type*/>::type
foo(T) {
std::cout << "Derived from Base." << std::endl;
}
// If the return type of foo() is not void, add where indicated.
template <typename T>
typename std::enable_if<!std::is_base_of<Base, T>::value /*, some_type*/>::type
foo(T) {
std::cout << "Not derived from Base." << std::endl;
}
int
main() {
Derived d;
NotDerived nd;
foo(d);
foo(nd);
}
答案 1 :(得分:0)
像这样使用std::enable_if
和std::is_base_of
:
template <typename T, typename = enable_if<is_base_of<mom, T>::value>::type>
void Iacceptonlysonsofmom(T x)
{
}
如果您无法使用C++11
,则可以使用Boost enable_if_c
和is_base_of
来实现相同目标。在上面的代码中,您需要将enable_if
替换为enable_if_c
,并确保使用适当的命名空间。
答案 2 :(得分:0)
正如其他人所建议您可以使用enable_if
和SFINAE (Substition Failure Is Not An Error),但这可能会有问题。它可能在编译器之间很脆弱,如果没有正确完成可能会导致ODR出现问题,可能会导致与从其他作用域(ADL)引入的函数发生冲突,并且可能不是最佳选择。
您确实有一些不太变幻无常的替代选项,可能会让您的代码更易于理解和维护。一个选项(如评论中所述)是使用static_assert
和is_base_of
。到目前为止,这是(恕我直言)最简单的解决方案。此方法允许您维护函数的单个实现,并在类型不是基类Mom
或从中派生时强制编译时失败。
#include <type_traits>
struct Mom { };
struct Child : Mom { };
struct Uncle { };
template <typename T>
void AcceptOnlyMomAndChildren(T)
{
static_assert(std::is_base_of<Mom, T>::value, "Not derived from Base.");
}
int main()
{
Child child;
Uncle uncle;
AcceptOnlyMomAndChildren(child);
AcceptOnlyMomAndChildren(uncle); // Fails
}
如果需要提供多个函数来处理非使用标记调度从特定基类派生的类型可能更有意义。这在编译器中变得不那么易变,并且必须更容易看到。如果您需要为从mom
派生的类型(在您的示例中)提供特殊处理,也可以轻松扩展它。
#include <type_traits>
#include <iostream>
struct Mom { };
struct Child : Mom { };
struct Uncle { };
template <typename T>
void Func(T&, std::true_type)
{
std::cout << "Derived from Base." << std::endl;
}
template <typename T>
void Func(T&, std::false_type)
{
std::cout << "Not derived from Base." << std::endl;
}
template <typename T>
void Func(T& arg)
{
Func(
arg,
typename std::conditional<
std::is_base_of<Mom, T>::value,
std::true_type, std::false_type>::type());
}
int main()
{
Child child;
Uncle uncle;
Func(child);
Func(uncle);
}
在上面的示例中,std::conditional
用于指定附加参数的类型,以确定调用Func
的哪个实现。您可以使用自己的类型特征方案替换它,以便在必要时支持其他实现。