如果这个问题之前已经有人问过并回答过,我表示歉意,但我现在一直在寻找一个可以理解的解决方案,但没有任何乐趣。
我正试图实现一个简单的类层次结构,在基类中定义了操作符重载(因为这些操作符在不同的派生类之间不会有区别)。 然而,由于这些操作符大多需要返回一个新的对象,无论我们在哪个派生类的上下文中,我假设它们需要被声明为一个模板方法,然而,当我试图这样编译时,链接器给了我一个 "未解决的外部符号 "错误......
举个例子。
/// This is in the class header file
class Base
{
// Declare all the base storage and methods ...
public:
template<class T>
friend T operator+(const T& lhs, const T& rhs);
// .... other stuff in here.
}
/// Then in the implementation file
T operator+ (const T& lhs, const T& rhs)
{
return T(lhs->m_1 + rhs->m_1, lhs->m_2);
}
我希望这将导致我可以这样声明派生对象。
class Derived : public Base
{
// ... Add the derived class functionality
// -- Question: Do I need to do anything in here with operator+ ???
}
Derived A();
Derived B();
Derived C = A + B;
这就是我所希望的结果 但如果不在每个派生类中定义操作符 我就无法在C++中实现这个功能 因为模板方法会导致链接器错误
是我遗漏了一些显而易见的根本性的东西,还是在C++中根本没有简单的方法来实现这个功能?
你的评论中指出了模板的 "实现文件中",这很可能是你的问题的原因。函数模板声明(如 T operator+(const T&, const&);
声明必须与之链接的符号--但它需要一个 实例化 的某处。
只需简单地定义该模板的 template
源文件中的函数实际上并不实例化代码 -- 它需要明确地对每个类型的具体实例进行链接,或者在打算调用它的地方有可见的函数模板定义(见 本回答 了解更多细节)。)
在很多情况下,最好是在头文件中定义函数模板,这样模板的任何调用者都可以实例化函数,而不需要与其他地方的现有实例进行链接。
也就是说...
你可能需要重新考虑一下你目前的做法。你的 operator+
模板不限制什么类型的 T
可以考虑,这将导致 operator+(const T&, const T&)
是一个可行的过载 任何 T
类型,但还没有一个 operator+
但前提是在重载解析期间声明是可见的。这可能会导致其他奇怪的编译器链接器错误。
有几种方法可以解决约束类型的问题;最简单的方法可能是使用SFINAE来约束它,通过检查 T
源于 Base
.
例如:
/// This is in the class header file
class Base
{
// Declare all the base storage and methods ...
public:
template<class T, class>
friend T operator+(const T& lhs, const T& rhs);
// .... other stuff in here.
}
// Note: In the same header!
// This only enables + if 'T' derives from 'Base'
template <typename T, typename = std::enable_if_t<std::is_base_of<Base,T>::value>>
T operator+(const T& lhs, const T& rhs)
{
return T(lhs->m_1 + rhs->m_1, lhs->m_2);
}