函数重载和模板

Function overloading and template

我有一个重载函数,它们的定义是一样的,只有一个参数改变了。 所以,我尝试创建一个模板函数,但是当我调用它时 我遇到了符号查找错误。

头文件

void func(Myobject obj);
void func(MySecondObject obj);

源文件

template<typename T>
void func(T obj) { obj.foo(); }

测试文件

#include "MyHeaderFile.h"

func(MySecondObject()); // symbol lookup error at runtime

谢谢。

如果你说

void func(Myobject obj);
void func(MySecondObject obj);

然后你向编译器保证它最终会找到

void func(Myobject obj)
{ /* implementation */ } 

void func(MySecondObject obj)
{ /* implementation */ }

由于你没有提供这些实现(你声明的这些符号没有定义),你会得到一个错误。

然而你可以做的是:

Header 文件

void func(Myobject obj);
void func(MySecondObject obj);

源文件

template<typename T>
void func_impl(T obj) { obj.foo(); }

void func(Myobject obj) { func_impl(obj); }
void func(MySecondObject obj) { func_impl(obj); }

这允许您为您的用户声明和定义 "real" (non-templated) 函数,但您仍然可以通过将工作委托给同一个模板函数来实现所有这些函数。最佳做法是将 func_impl 放入未命名的命名空间 (namespace /* no name here */ { /* code goes here */ }),这将使其成为该翻译单元的内部(并且还明确表示它不打算成为 seen/used其他代码,无需 cross-reference header).


(以下内容已在 Why can templates only be implemented in the header file? 讨论过)。

另一种方法是在 header 中声明函数模板,然后在源文件中定义它并为您想要的类型提供显式实例化:

Header 文件

template<class T>
void func(T obj);

// Explicit instantiation declarations
extern template void func<Myobject>(Myobject obj);
extern template void func<MySecondObject>(MySecondObject obj);

源文件

template<typename T>
void func(T obj) { obj.foo(); }

// Explicit instantiation definitions
template void func<Myobject>(Myobject obj);
template void func<MySecondObject>(MySecondObject obj);

这种方法明显更冗长,可能会让非 template-affine 的用户感到困惑,并且尝试将其与错误的类型一起使用会导致链接器错误,而不是更好的编译器错误,因此上面的第一个解决方案很容易就是最合适的。

或者您可以在 header 文件中定义整个模板。不过,可以有充分的理由避免这种情况。

您似乎想要一个模板函数,其中包含 MyObjectMySecondObject 的两个显式实例化。模板函数声明应该在你的 header 中:

template<typename T>
void func(T obj);

然后在相应的源文件中你应该提供通用实现+显式实例化:

#include "header.hpp"

template<typename T>
void func(T obj)
{
  obj.foo();
}

template void func<MyObject>(MyObject obj);
template void func<MySecondObject>(MySecondObject obj);

然后您可以在代码中使用这两个版本:

func(MyObject());
func(MySecondObject());

但使用另一个模板参数调用 func,例如func('c') 将导致未定义的引用。

cpp reference 节 "Explicit instantiation".

我建议在源文件中定义模板专业化。它隐藏了当前翻译单元中的模板专业化。

MyHeaderFile.h

template <typename T>
void func(T obj);

MyHeader.cpp

#include <iostream>
#include "MyHeaderFile.h"

template <typename T>
void func(T obj)
{
  std::cout << "function name: " << __func__;
}

template void func<MySecondObject>(MySecondObject obj);

template void func<Myobject>(Myobject obj);

希望这个回答能解决您的问题。