在 child class 中定义可变函数特化

Defining variadic function specialization in child class

我正在尝试允许 child class 定义可变函数特化。例如:

#include <iostream>
#include <vector>
#include <memory>

class BaseClass
{
public:
    BaseClass() {};
    virtual ~BaseClass() {};

    template<typename GenericData>
    void ReceiveData(GenericData &inData)
    {
        throw std::runtime_error("Undefined");
    }
};

class ReceiveInt : public BaseClass
{
    void ReceiveData(int & inData)
    {
        std::cout << "I know what to do!";
    }
};


int main(int argc, char* argv[])
{
    std::vector<std::shared_ptr<BaseClass>> classHolder;
    classHolder.push_back(std::make_shared<ReceiveInt>());

    int test = 1;
    classHolder.front()->ReceiveData(test);

    return 0;
}

但不幸的是,这不起作用,因为调用了 BaseClass ReceiveData 函数。这甚至可能吗?

编辑 1 正如人们所指出的,我的符号非常错误。看来我今天学到的比我想象的要多。

Is this even possible?

我不这么认为。

动态调度仅适用于 virtual 成员函数。

成员函数模板可能不是virtual

如果您可以使用常规成员函数,即不是成员函数模板,那么您可以制作它们 virtual。那行得通。

我认为您可能混淆了您的术语。 BaseClass::ReceiveData 是一个模板化方法,采用 模板参数 GenericData。可变参数函数采用运行时确定的多个 参数

ReceiveInt 中,您没有对任何内容进行专门化,因为 ReceiveInt::ReceiveData 不是模板化方法。事实上,即使它是模板化的,也不可能在你的例子中调用。指向 BaseClass 的指针如何知道如何在它指向的派生 class 中调用模板特化?

你可以BaseClass::ReceiveDatavirtual。这允许您在基 class 中覆盖它,并且仍然使用指向 BaseClass 的指针调用它。不幸的是,模板是一种编译时语言特性,而动态分派是一种运行时特性——在这种情况下,你不能同时拥有这两种特性。

参考资料

您必须先转换为派生类型,使用基 class pointer/reference 是不可能的,因为基 class 只会知道它自己的实现。这甚至不是您可以对派生类型使用递归依赖的情况,因为派生类型在实例化基础时尚未定义。

如果您确实强制转换为派生类型,那么它将能够按照您的需要解析派生成员。

你在这里混淆了一些概念。

首先,这里没有可变模板作为下面的 ReceiveData 函数:

template<typename GenericData>
void ReceiveData(GenericData &inData)
{
    throw std::runtime_error("Undefined");
}

是模板成员函数。

那么,如果你想在派生的class中覆盖一个方法,正确的方法是使用virtual函数,大概是一个pure基 class 中的 virtual 函数和派生 class 中带有 override 说明符的 virtual 函数].

但是,virtual 函数将您限制为一组固定类型,因为没有模板虚函数。不过,您可以尝试使用 CRTP

template<typename T>
class Base {
public:
    void receiveData(const T&) {}
};

class ReceiveInt : public Base<int> {};

模拟了一种静态多态性。以下:

ReceiveInt{}.receiveData(int{});

receiveData 来自基础 class,实例化为 int

您的代码中没有其他人已经解释过的可变参数模板。 但是您可以使用这样一个事实,即模板化 class 方法是在第一次调用时实例化的。但是这里没有虚拟覆盖。 在此示例中,您可以在 Base 和 Derived classes 中定义方法模板的不同实现,但您已明确告诉编译器使用哪一个。 在没有显式转换的情况下,无法通过 Base class 指针使用 Derived class 方法:

#include <iostream>
#include <memory>
using namespace std;

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

    template<typename T>
    void ReceiveData(T)
    {
        throw std::runtime_error("Undefined");
    }
};

class Derived : public Base
{
public:
    template<typename... Args >
    void ReceiveData(Args... args)
    {
        (void)std::initializer_list<int>{(std::cout << args << std::endl, 0)...};
    }
};


int main()
{
    Base b;
    //  b.ReceiveData(1);       //-> this calls base class method

    Derived d;
    d.ReceiveData(1);           // this calls the method in the derived class

    d.ReceiveData(2, "hello");  // this calls the method in the derived class

    Base* b2 = new Derived();
    // b2->ReceiveData(3);      // this will instantiate and call the base class method
                                // thus raising an exception
                                // because no virtual overriding of templated methods

    ((Derived*)b2)->ReceiveData("world",1); // this will instantiate and call the derived class 
                                            // method, then because of explicit casting the 
                                            // compiler knows which class to target

    return 0;
}

现场演示:https://wandbox.org/permlink/K0qEAC7C7yzg6gYL