模板函数中的多态

时间:2019-03-25 15:49:13

标签: c++ templates polymorphism

我想使用模板函数来处理多态类和非多态类。这是3个基本课程。

it('should add Pragma header to request', () => {
        const req = new Http();
        expect(req.request.headers.has('Pragma')).toBeTruthy();
        expect(req.request.headers.get('Pragma')).toEqual('no-cache');
    });

it('should add Cache-Control header to request', () => {
        const req = new Http();
        expect(req.request.headers.has('Cache-Control')).toBeTruthy();
        expect(req.request.headers.get('Cache-Control')).toEqual('no-cache');

由于 NotDerived 没有虚函数,所以我不能使用dynamic_cast,接下来是模板函数:

class NotDerived
{

};

class Base
{
public:
    virtual ~Base() {}
    void base_method() {}
};

class Derived : public Base
{

};

主要功能是这样做的:

template<class T>
auto foo(T& some_instance)
{
    if (std::is_base_of_v<Base, T>)
    {
        //CASE_1: Works for d and b
        /*some_instance.base_method();*/

        //CASE_2: Works for d and b
        /*auto lamb1 = [](T& some_instance) {some_instance.base_method(); };
        lamb1(some_instance);*/


        auto lamb2 = [](T& some_instance) {((Base&)some_instance).base_method(); };
        lamb2(some_instance);
    }
}

现在,我理解了为什么在传递void main() { Derived d{}; Base b{}; NotDerived nd{}; foo(d); foo(b); foo(nd); } 变量的情况下CASE_1不起作用,但是我不明白的是,我必须在lamb2函数中显式转换nd才能调用base_method。

有人可以解释为什么CASE_1,CASE_2不起作用而CASE_3起作用的原因。 通过工作,我的意思是在没有dynamic_casting的情况下尽可能地调用base_method。

也可以使用some_instance处理静态多态或编译多态的情况(希望这样命名是合法的)

2 个答案:

答案 0 :(得分:5)

情况3不起作用。您正在强制转换为不相关的类型,并使用该临时类型来调用未定义行为的函数。

使用问题

if (std::is_base_of_v<Base, T>)
{
    //...
}

...部分中的所有内容都必须能够编译。您需要的是一种仅在T是所需类型时调用该代码的方法。您可以像使用constexpr if一样

if constexpr (std::is_base_of_v<Base, T>)
{
    some_instance.base_method();
}
else
{
    // do something else since T isn't a Base or derived from Base
}

现在,如果std::is_base_of_v<Base, T>为假,则some_instance.base_method();将被丢弃并且从不编译。

答案 1 :(得分:1)

您应该查看有关SFINAE的官方文档。无论如何,if中的代码都将被编译,所以这就是为什么它不会编译。

如果您使用的是C ++ 17,则可以用constexpr if替换它,它将在编译期间评估if中的信息,并在需要时忽略代码:

template<class T>
auto foo(T& some_instance) {
    if constepxr (std::is_base_of_v<Base, T>) {
        auto lamb2 = [](T& some_instance) {((Base&)some_instance).base_method(); }
        lamb2(some_instance);
    } else {
        // Whatever you want to do
    }
}

如果您使用的是旧版本的C ++,则简单的函数重载可能会解决您的问题:

template<class T>
auto foo(T& some_instance) {
   // Do whatever
}

auto foo(Base& some_instance) {
    auto lamb2 = [](T& some_instance) {((Base&)some_instance).base_method(); }
    lamb2(some_instance);
}

或者,您可以使用SFINAE机制通过使用std::enable_if来窥视正确的功能:

template <typename T>
typename std::enable_if<std::is_base_of<Base, T>::value, void>::type
foo() {
   auto lamb2 = [](T& some_instance) {((Base&)some_instance).base_method(); }
   lamb2(some_instance); 
}

template <typename T>
typename std::enable_if<!std::is_base_of<Base, T>::value, void>::type
foo() {
   // Do whatever
}