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

Call right template function via base class pointer

本文关键字:函数 基类 指针 调用      更新时间:2023-10-16

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

这是我所拥有的:

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);

我想在这个例子中将参数处理为整数, 无论参数是什么类型。它调用正确的函数 但是该值是垃圾,因为双精度被解释为整数 而不是被转换。

我看过其他问题(和其他网站),但不能 查找匹配项或解决方案,例如 调用派生类的模板函数

解决方案可能是CRTP,但我无法弄清楚如何 来使用它。应用程序代码应保持如下, 类定义可以更改。此代码的原因是 它是从某些 XML 在运行时生成和使用的 配置文件。所以类型在 函数调用。

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

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

或者阻止使用双精度自动创建函数 因此,参数将转换为整数,就像在 非模板化函数。

感谢您的任何帮助。

编辑:下一个解决方案

这看起来有效吗?它不需要强制转换,我们只需要模板的少数不同的基本类型,因此不会有很多重定向器功能。而且它应该仍然是有效的(没有类型信息等)。 我也在发布它,以防其他人遇到类似的问题。

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

谢谢

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

为了简化起见,您的代码类似于以下内容:

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_castthis指针指向不相关的指针TTemplateTest<double>*。但是this指针确实是一个TTemplateTest<int>*,这两个类除了都派生自CTemplateTest之外没有任何关系。所以这只是简化的情况。

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

一些观察:

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

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

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

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