通过基类指针调用正确的模板函数

时间:2018-01-25 14:02:31

标签: c++ templates derived-class

我想我已经接近解决方案,但我错过了最后一步。 我想调用一个模板化的成员函数,我只有一个指针 到基类,类型已经预定义,所以不应该 取决于实际的参数类型。

这就是我所拥有的:

template <typename T> class TTemplateTest;

class CTemplateTest
{
public :
    CTemplateTest(){};
    template <typename T> double Process(T atValue)
    {
        return static_cast<TTemplateTest<T>* >(this)->Process(atValue);
    }
};
//------------------------------
template <class T>
class TTemplateTest:public CTemplateTest
{
    public :
        TTemplateTest() : CTemplateTest(){};
        virtual double Process(T atNewValue) {return atNewValue;};
};
//------------------------------
template <class T>
class TTemplateTestInt:public TTemplateTest<T>
{
public :
    TTemplateTestInt(){};
    virtual double Process(T atNewValue);
};
//------------------------------
template <class T> double TTemplateTestInt<T>::Process(T atNewValue)
{
    return atNewValue;
}

CTemplateTest* pTTest = new TTemplateTestInt<int>();

// application code
double d = 5.5;
double r;
r = pTTest->Process(d);

我想在这个例子中将参数处理为整数, 无论论证是什么类型。它称之为正确的功能 但是值是垃圾,因为double被解释为整数 而不是转换。

我已经查看了其他问题(以及其他网站),但却没有 找到匹配或解决方案,例如 calling a template function of a derived class

解决方案可能是CRTP,但我无法弄清楚如何 使用它。应用程序代码应保持这样, 类定义可以改变。这段代码的原因是 它是从某些xml在运行时生成和使用的 配置文件。所以这种类型并不是真正知道的 功能调用。

如果我可以使用定义的类型,那可能会有所帮助,例如:

template <typename T> double Process(T atValue)
{
    return static_cast<TTemplateTest<T>* >(this)->Process((this::type)atValue);
}

或者阻止使用double自动创建函数 所以参数会转换为整数 一个非模板化的函数。

感谢您的帮助。

编辑:下一个解决方案

这看起来有效吗?它不需要转换,我们只需要一些不同的基本类型的模板,因此不会有很多重定向器功能。它应该仍然有效(没有typeinfo等)。 我也发布它以防其他人有类似的问题。

class CTemplateTest
{
public :
    CTemplateTest(){};
    virtual inline double Process(double adValue)=0;
    virtual inline double Process(int aiValue)=0;
};
//------------------------------
template <class T>
class TTemplateTest:public CTemplateTest
{
    public :
        TTemplateTest() : CTemplateTest(){};
        virtual inline double Process(double adValue) {
            return ProcessImp((T)adValue);
        }
        virtual inline double Process(int aiValue) {
            return ProcessImpl((T)aiValue);
        }
        virtual double ProcessImpl(T atNewValue)=0;
};
//------------------------------
template <class T>
class CTemplateTestInt:public TTemplateTest<T>
{
public :
    CTemplateTestInt(){};
    virtual double ProcessImpl(T atNewValue) {return atNewValue;};
};

然后用

给出所需的结果
CTemplateTest* pTTest = new TTemplateTestInt<int>();

// application code
double d = 5.5;
double r;
r = pTTest->Process(d);
// -> r = 5

由于

2 个答案:

答案 0 :(得分:3)

您的代码在命名和逻辑方面看起来相当混乱。我不知道你想做什么,但我可以解释为什么你的代码会导致奇怪的行为,这也表明你的代码中存在一些基本的设计缺陷。

为简化起见,您的代码与此类似:

class A {};

class B : public A {};

class C : public A {};

int main () {
    A *a_ptr = new B {};
    C *c_ptr = static_cast<C*>(a_ptr);
}

没有reinterpret_cast,但此代码仍会破坏类型系统,并会导致未定义的行为。因为BC无关,即使它们都来自A

返回您的代码,class CTemplateTest,功能

template <typename T> double Process(T atValue)
{
    return static_cast<TTemplateTest<T>* >(this)->Process(atValue);
}

将通过模板参数推导获得类型T从任何预定义类型获取。因此,pTTest->Process(d)会将类型T推断为双精度,并且在该函数中,static_cast指向不相关指针this的{​​{1}}指针。但是TTemplateTest<double>*指针确实是this,这两个类没有任何关系,除了两个类都来自TTemplateTest<int>*。所以它只是简化的案例。

我不知道如何修复此代码......

答案 1 :(得分:1)

一些观察结果:

1)您的基类没有虚函数,但您的派生类每个都有唯一的,不相关的虚函数。它们不会覆盖任何东西,所以有点无意义是虚拟的。

2)基类不知道实例化派生类型的类型。当调用CTemplateTest :: Process时,该T是为函数调用推导出的参数,并且与用于派生类型的T无关。您只是将对象强制转换为使用您提供的类型实例化的模板,而忽略对象实际所在的类型。这说明了垃圾;这是未定义的行为。

3)没有模板虚拟功能这样的东西。非此即彼;接受你的选择。这基本上就是我认为你试图模拟的东西。您希望相同的函数采用任何类型的参数,并将其作为该类型传递给派生类型,派生类型知道如何以自己的模板方式处理它。我不确定一种令人满意的方法来实现这一目标。

一种想法是预先确定一组固定的类型,您将接受并单独处理它们,每个支持类型一个虚函数。您可以使用模板参数列表使其更加灵活,并使用编译器生成函数,但我完全没有想到这种方法。 :)