模板和继承过滤

3
这种使用模板的方式是否合法?
class Foo {};

class Bar : public Foo {};

//Only accept classes, which inherit Foo.
template<Foo T>
void awesomeFunction() {
    Foo *f = new T();
}

int main() {
    awesomeFunction<Bar>();
}

有没有另一种编译时和异常安全的方法?

我要冒险猜测你的意思是 template <class T>,而不是其他的。 - SirGuy
4个回答

3
您可以使用SFINAE:
template<typename T, std::enable_if_t<std::is_base_of<Foo, T>::value>* = nullptr>
void awesomeFunction() {
    Foo *f = new T();
}

3

通过使用概念,你将能够编写:

template<class T>
    requires std::is_base_of_v<Foo, T>
void awesomeFunction()
{
   // ...
}

在它们成为标准之前,其他答案中提出的SFINAE和static_assert解决方案将起到作用。


使用 requires 与 max66s 和 Jarod42s 的答案中的解决方案有什么区别吗? - user4937236
@ShroomPow - 在我看来更简单、更优雅;不幸的是,它需要从C++20开始才能使用该概念(据我所知)。 - max66

2

这种使用模板的方式是否合法?

不合法,因为使用

template<Foo T>

您需要将类型为Foo对象作为模板参数(而类型为Foo的对象无法作为模板参数),并调用

awesomeFunction<Bar>();

你需要传递一个类型,而不是一个对象。

正确的解决方案是像Jarod42所示的那样,接收一个类型 (template <typename T>),并通过SFINAE启用/禁用函数。

另一种使用SFINAE的方法是,如果你至少可以使用C++11,

template <typename T>
typename std::enable_if<std::is_base_of<Foo, T>{}>::type awesomeFunction() {
    Foo *f = new T();
}

使用C++14可以简化为以下内容:

template <typename T>
std::enable_if_t<std::is_base_of<Foo, T>{}> awesomeFunction() {
    Foo *f = new T();
}

返回值怎么办?我应该把返回类型说明符放在哪里? - user4937236
1
@ShroomPow - std::enable_if 的第二个模板参数是返回类型;因此,您可以使用 typename std::enable_if<std::is_base_of<Foo, T>{}, void>::type。但是,void 是第二个模板参数的默认类型,因此在您的情况下,即使返回类型为 void,也可以避免显式指定它(对不起,我这里有个双关语)。 - max66
非常感谢你,max66;我会加一个 +1。 - user4937236
它... 它押韵。是的。 - user4937236

1
您可以使用 is_base_of 类型特征和 static_assert。如果 T 不是从 Foo 派生的,它将发出相应的错误消息并停止编译。
#include <type_traits>

template<typename TDerivedFromFoo>
void awesomeFunction()
{
    static_assert
    (
        ::std::is_base_of<Foo, TDerivedFromFoo>::value
    ,   "This function only accept classes, which inherit Foo."
    );
    Foo * f{new TDerivedFromFoo{}};
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接