在派生类实例上调用使用基类实例实例化的模板化函数

Calling a templated function instanciated with base class on a derived class instance

提问人:CocoLAsticot 提问时间:8/2/2023 更新时间:8/2/2023 访问量:65

问:

我的问题与这个问题非常相似,但我不确定同样的答案是否适用于这里。

我有一个模板化函数,其代码相对较重,因此我在单独的 .cpp 文件中定义它,并为我需要的类型显式实例化它:

foo.h

template <typename T>
void foo(T &arg);

foo.cpp

template <typename T>
void foo(T &arg)
{
... //Long code
}

template
void foo<Type1>(Type1 &arg);

template
void foo<Type2>(Type2 &arg);

现在我还希望能够调用对象,并带有来自 的派生类。我可以在没有非模板化函数的情况下做到这一点,但模板化的函数有链接器问题:foo()Type3Type3Type2

class Type3 : public Type2
{ ... }

void foo1(Type2 &arg)
{ ... }

...

Type3 var;
foo1(var); //Runs fine
foo(var); //Linker error

由于我显式实例化以接受变量,因此我真的不明白为什么从派生到基函数的相同转换不会像非模板化函数那样自动应用......foo()Type2

我知道我可以通过编写 或 来运行此代码,但是有没有一种解决方案不需要更改我调用函数的方式,也不需要显式实例化来接受变量(以避免增加编译时间)?foo<Type2>(var)foo((Type2&)var)fooType3

C++ 函数 模板 继承

评论

1赞 HolyBlackCat 8/2/2023
“我真的不明白为什么从派生到基数的相同转换不会自动适用”因为显式实例化并不意味着其他类型不能作为参数传递。此外,您没有在标头中声明实例化,因此编译器无法知道它们的存在(尽管添加它们不会更改任何内容)。
1赞 HolyBlackCat 8/2/2023
我看到的唯一选择是编写一个特征,该特征返回类型的适当基,并具有一个包装模板函数来转换为该类型。也许添加 ,并在你的特征中读取它(如果它存在)。using base = Type2;class Type3
2赞 Sam Varshavchik 8/2/2023
foo()可以接受任何类型作为其模板参数。仅仅因为类型 A 是从类型 B 派生而来的,将 A 传递给模板函数不会将 B 推导出为模板参数,而 A 会推导出为模板参数,而不是 B。如果要调用 B 的模板实例,请不要推导它,而是显式指定模板参数。
1赞 CocoLAsticot 8/2/2023
感谢您的回答,我明白为什么我想做的事情行不通。由于似乎没有适合我需求的奇迹解决方案,我可能不得不以不同的方式重新编写整个代码。
2赞 Jarod42 8/2/2023
从显示的代码中,标头中应该只有常规重载。然后,cpp 文件中的定义可能会调用模板实现。void foo(Type1&); void foo(Type2 &);

答:

4赞 Jarod42 8/2/2023 #1

我有一个模板化函数,其代码相对较重,因此我在单独的 .cpp 文件中定义它,并为我需要的类型显式实例化它:

因此,只需公开这些类型的重载:

void foo(Type1&);
void foo(Type2&);

在源文件中,转发到模板实现:

template <typename T>
void fooImpl(T &arg)
{
    // Long code
}

void foo(Type1 &arg) { fooImpl(arg); }
void foo(Type2 &arg) { fooImpl(arg); }