将派生类传递给专用于基类的模板函数
Passing a derived class to a template function specialized with base class
以下代码编译正常,但会产生链接器错误:
class Base {};
class Derived : public Base {};
template <typename T>
void f(const T& value);
template <>
void f(const Base& value) {
// ...
}
int main() {
Base b;
f(b);
Derived d;
f(d); // This line causes linker error.
return 0;
}
是否可以在不为派生类添加重复f()
专用化的情况下使此代码编译和链接?
谢谢。
P.S 我正在使用 clang,Apple LLVM 版本 6.0 (clang-600.0.56)(基于 LLVM 3.5svn)。
P.P.S 链接器错误为:
Undefined symbols for architecture x86_64:
"void f<Derived>(Derived const&)", referenced from:
_main in test2-4245dc.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
发生链接器错误是因为尚未定义(仅声明)函数模板
template <typename T>
void f(const T& value);
为了避免它,定义上面的模板,你的代码将编译,但大概它仍然没有做你想要的。
当使用类型为 Derived
的参数调用 f
时,与您的专用化相比,上述模板更匹配,因为后者需要派生到基础的转换,而前者不需要。
通过使用 enable_if
仅当推导的模板参数类型不是 Base
或派生自 Base
的类型时,才允许第一个模板参与重载解析,从而实现所需的行为。
template <typename T>
typename std::enable_if<!std::is_base_of<Base, T>::value>::type
f(const T& value) {
}
并改变其他f
,使其不是专业化,而只是超载。
void f(const Base& value) {
// ...
}
现场演示
通常,首选重载函数模板而不是专用化。阅读本文以了解函数模板专用化的陷阱。
假设您确实需要模板,并且必须具有Base
的所有派生物才能调用专用化,则可以将专用化替换为重载,并为使用类型特征从Base
派生的所有类型禁用模板:
template <typename T, typename std::enable_if<!std::is_base_of<Base, T>::value>::type>
void f(const T& value);
// no template
void f(const Base& value)
这样,只有 Base
的重载可用于派生类型。
问题就在这里:
template <typename T>
void f(const T& value);
此函数未定义,但是当您调用
f(d)
与Derived d;
Base
专用化template<> void f(const Base& value)
参与f(d)
的重载解析,但它不如完整模板template <typename T> void f(const T& value)
合适。
一个想法是完全删除专用化,只定义完整的模板,代码可能会做你想要的。
正如其他人所说,您尚未定义泛型模板函数,它是派生类型的最佳候选项。如果要更好地了解模板函数重载解析的工作原理,请参阅此处的参考:http://en.cppreference.com/w/cpp/language/function_template#Function_template_overloading
你的例子有点做作(也许是为了简洁起见)。但通常,仅当需要为特定类型实现特殊逻辑,或者希望在单独的源文件中定义模板类和函数并且只需要/想要支持某些类型时,才应提供模板专用化。也许这就是您实际想要的,但泛型被称为泛型是有原因的。
- 虚拟基类函数中派生类的大小
- 无法访问基类函数 C++
- 如何使派生类函数在调用时始终调用相同的基类函数?
- C++虚拟函数:基类函数是调用的,而不是派生的
- Qt基类函数定义
- 添加字符串类型的类成员会导致调用基类函数而不是子函数
- 有没有办法调用基类函数,该函数在使用私有继承的派生类中被覆盖?
- C++ - 基类函数指针调用的替代方法
- 什么更有效率?在重载函数中或通过在基类函数中检查对象类型来实现
- 重载基类函数是不好的做法吗?
- 在 qml 中公开基类函数
- 调用基类函数时强制使用类名?
- 如何判断哪个派生的类对象称为基类函数
- 获取具有基类函数的派生类
- 有没有办法从基类函数参数中推断出模板参数
- 私有非虚拟基类函数被称为派生类中的函数
- 模板基类函数成员的别名
- 如何用相同的签名从main调用基类函数
- C++ 如何从 main 调用派生的基类函数
- memcpy派生类到基类,为什么还调用基类函数