将派生类传递给专门用于基类的模板函数 [英] Passing a derived class to a template function specialized with base class
问题描述
以下代码可正常编译,但会产生链接器错误:
The following code compiles fine, but produces a linker error:
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()
专业化条件的情况下,使该代码进行编译和链接?
Is it possible to make this code compile and link without adding a duplicate f()
specialization for the derived class?
谢谢.
P.S我正在使用clang,Apple LLVM 6.0版(clang-600.0.56)(基于LLVM 3.5svn).
P.S I'm using clang, Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn).
P.P.S链接器错误是:
P.P.S The linker error is:
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)
推荐答案
发生链接器错误是因为您尚未定义(仅声明)函数模板
The linker error occurs because you haven't defined, only declared, the function template
template <typename T>
void f(const T& value);
为避免这种情况,请定义上面的模板,您的代码将被编译,但是大概它仍然无法满足您的要求.
To avoid it, define the above template and your code will compile, but presumably it still doesn't do what you want.
当使用类型为 Derived
的参数调用 f
时,与您的专业化相比,上面的模板更好地匹配,因为后者需要从派生到基数的转换,而前者没有.
When calling f
with an argument of type Derived
the above template is a better match compared to your specialization because the latter requires a derived-to-base conversion while the former doesn't.
您可以使用 enable_if
仅在推导的模板参数类型不是 Base
或从 Base
派生的类型时,才允许第一个模板参与重载解析.
You can achieve the behavior you want by using enable_if
to allow the first template to participate in overload resolution only if the deduced template argument type is not Base
or a type derived from Base
.
template <typename T>
typename std::enable_if<!std::is_base_of<Base, T>::value>::type
f(const T& value) {
}
并更改另一个 f
,所以它不是专门化的,而只是重载.
And change the other f
so it's not a specialization, but just an overload.
void f(const Base& value) {
// ...
}
通常,重载函数模板胜于专业化.阅读此,以了解功能模板专业化的陷阱.
In general, prefer overloading function templates over specialization. Read this to learn about the pitfalls of function template specialization.
这篇关于将派生类传递给专门用于基类的模板函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!