我有两个模板类,并且Leaf<T>
是从Base<T>
派生的,然后我开发了一个模板函数,该函数使用Base<T>
的引用作为其参数。并在其源文件中设置该函数的定义和实例化。
一旦我尝试将Leaf<T>
作为该函数的参数传递,就会发生此问题。编译器尝试使用Leaf<T>
查找没有以前的自动约定的符号。
// foo.h
#ifndef __FOO_H_INCLUDED__
#define __FOO_H_INCLUDED__
#include <base.h>
template <typename T>
void Foo(T &value);
#endif // __FOO_H_INCLUDED__
// foo.cpp
#include <foo.h>
#include <iostream>
template <typename T>
void Foo(T &value)
{
std::cout<<value.getValue()<<std::endl;
}
template void Foo(MyBase<int> &value);
// main.cpp
#include <leaf.h>
#include <foo.h>
int main()
{
int i = 20;
MyLeaf<int> leaf;
leaf.setValue(i);
Foo(leaf);
}
上面的代码片段将在链接中引发“ undefined 的引用”异常。将调用重构为
Foo<MyBase<int> >(leaf)
将解决问题,但不是我想要的。并且显式实例化所有潜在的派生类型也是不可能的,因为无法知道它们有多少种。那么,有什么方法可以使链接程序识别基本类型的符号,而不是找到精确的符号并引发错误?
最佳答案
在一个翻译单元中添加显式模板实例化必须与一个显式模板实例化声明配对,以确保编译器不会尝试执行隐式实例化。否则,程序格式不正确。
除此之外,除了Foo<MyLeaf<int>>
之外,您无法使用模板参数推导来推导设置方式。但是,通过一些调整,我们可以使其正常运行。在标题中:
template <typename T>
void Foo(MyBase<T> &value);
extern template void Foo(MyBase<int> &value);
并在您的实施文件中:
template <typename T>
void Foo(MyBase<T> &value)
{
std::cout<<value.getValue()<<std::endl;
}
template void Foo(MyBase<int> &value);
现在,推导规则和重载解析应正确匹配功能。我们所做的就是转移负担。现在,该函数始终期望从
MyBase
实例化一个类。并且由于从MyLeaf
实例化的每个类也都从MyBase
实例化的类派生,因此您可以看到它的去向。我们满足了参数的模板要求,只是让它从中推导T
。