我有一个模板类"Extra",在"extra.h"中定义了一个函数"doSomething",并且我定义了两个"doSomething"的特化版本。两个不同的函数创建了类型为"Extra"的对象,每个对象都具有不同的类型参数,并分别调用其中一个特化版本。两个客户端函数"client1"和"client2"分别在两个文件"client1.cpp"和"client2.cpp"中定义。在第三个文件中,"main"先调用"client1",再调用"client2"。现在,"client1.cpp"和"client2.cpp"都#include "extra.h"。我得到一个链接错误,指出"doSomething"有(2)个多重定义。当然,如果我将"client1"和"client2"的定义放入单个源文件中,则不会有此问题。有没有办法保留我的不同文件安排的方式来处理"client1"和"client2"?以下是我的代码。谢谢!
// extra.h
#ifndef EXTRA_H
#define EXTRA_H
template <typename T>
class Extra
{
public:
Extra(T);
~Extra();
T doSomething(T);
private:
Extra() {}
T m_value;
};
template <typename T> Extra<T>::Extra(T input) : m_value{input} {}
template <typename T> Extra<T>::~Extra() {}
template <> int Extra<int>::doSomething(int input)
{
return input * m_value;
}
template <> double Extra<double>::doSomething(double input)
{
return input + m_value;
}
template <typename T> T Extra<T>::doSomething(T input)
{
return input;
}
#endif
// client1.cpp
#include "extra.h"
#include <iostream>
void client1()
{
std::cout << "In client1." << std::endl;
Extra<int> extra(2);
int res = extra.doSomething(3);
std::cout << "Value: " << res << std::endl;
}
// client2.cpp
#include "extra.h"
#include <iostream>
void client2()
{
std::cout << "In client2." << std::endl;
Extra<double> extra(2.0);
double res = extra.doSomething(2.0);
std::cout << "Value: " << res << std::endl;
}
// main.cpp
#include <iostream>
void client1();
void client2();
int main()
{
std::cout << "In main." << std::endl;
client1();
client2();
return 0;
}
为了完整起见,这里是我的链接器错误:
$ g++ -std=c++11 -o client client1.cpp client2.cpp main.cpp
duplicate symbol __ZN5ExtraIiE11doSomethingEi in:
/var/folders/mf/jdvfkpms609206zpz8x5237r0000gn/T/client1-6fa7ed.o
/var/folders/mf/jdvfkpms609206zpz8x5237r0000gn/T/client2-387444.o
duplicate symbol __ZN5ExtraIdE11doSomethingEd in:
/var/folders/mf/jdvfkpms609206zpz8x5237r0000gn/T/client1-6fa7ed.o
/var/folders/mf/jdvfkpms609206zpz8x5237r0000gn/T/client2-387444.o
ld: 2 duplicate symbols for architecture x86_64
inline
实际上是一个提示链接器的暗示,告诉它同一个函数可能有多个副本。当你直接在类内定义一个函数时,它会被隐式地视为内联函数。当你在头文件中定义函数并且不属于某个类(就像你所做的那样),你几乎总是需要显式地标记它们为内联函数,以避免链接错误。编译器是否将其内联是另一个问题。 - Pavel P