链接器抱怨多重定义,即使有包含警卫

时间:2017-11-28 10:56:15

标签: c++ templates

我无法弄清楚为什么代码无法编译,即使我有防护重复编译的包含保护

主类foo.h:

#ifndef FOO_H_INCLUDED
#define FOO_H_INCLUDED

#include <iostream>

class Foo;

template<int TDim>
struct Foo_Helper
{
    static bool Compare(const Foo& this_foo, const Foo& other_foo);
};

class Foo
{
public:
    Foo(const int& Value) : mValue(Value) {}
    virtual ~Foo() {}
    const int& Value() const {return mValue;}
    template<int TDim>
    bool Compare(const Foo& rother_foo) {return Foo_Helper<TDim>::Compare(*this, rother_foo);}
private:
    int mValue;
};

#endif

#include "foo.hpp"

foo.hpp定义模板特化:

#ifndef FOO_HPP_INCLUDED
#define FOO_HPP_INCLUDED

template<>
bool Foo_Helper<1>::Compare(const Foo& this_foo, const Foo& other_foo)
{
    return this_foo.Value() == other_foo.Value();
}

template<>
bool Foo_Helper<2>::Compare(const Foo& this_foo, const Foo& other_foo)
{
    return this_foo.Value() == other_foo.Value();
}

#endif

这两个源文件: src1.cpp:

#include "foo.h"

class Test1
{
public:
    bool test()
    {
        Foo f1(1);
        Foo f2(2);

        return f1.Compare<1>(f2);
    }
};

src2.cpp:

#include "foo.h"

class Test2
{
public:
    bool test()
    {
        Foo f1(1);
        Foo f2(2);

        return f1.Compare<2>(f2);
    }
};

的CMakeLists.txt:

set(file_list
src1.cpp
src2.cpp
)

add_library(Test SHARED ${file_list})

错误消息:

Linking CXX shared library libTest.so
CMakeFiles/Test.dir/src2.cpp.o: In function `Foo_Helper<1>::Compare(Foo const&, Foo const&)':
/home/hbui/workspace/c++/multiple_definition_error/foo.hpp:7: multiple definition of `Foo_Helper<1>::Compare(Foo const&, Foo const&)'
CMakeFiles/Test.dir/src1.cpp.o:/home/hbui/workspace/c++/multiple_definition_error/foo.hpp:7: first defined here
CMakeFiles/Test.dir/src2.cpp.o: In function `Foo_Helper<2>::Compare(Foo const&, Foo const&)':
/home/hbui/workspace/c++/multiple_definition_error/foo.hpp:13: multiple definition of `Foo_Helper<2>::Compare(Foo const&, Foo const&)'
CMakeFiles/Test.dir/src1.cpp.o:/home/hbui/workspace/c++/multiple_definition_error/foo.hpp:13: first defined here
collect2: error: ld returned 1 exit status
make[2]: *** [multiple_definition_error/libTest.so] Error 1
make[1]: *** [multiple_definition_error/CMakeFiles/Test.dir/all] Error 2
make: *** [all] Error 2

我认为包含守护已经阻止了foo.hpp中的两个函数被编译。但是,看起来每个cpp文件都编译自己的函数。在这种情况下,如何正确定义模板专用函数?

1 个答案:

答案 0 :(得分:2)

标题保护会停止在同一翻译单元中包含两次的标题。您的问题是Compare专精的定义将在两个翻译单元中定义,但不会标记为inline。这意味着当链接器尝试链接test1.cpp和test2.cpp生成的目标文件时,它会给出多重定义错误。如果您将特化标记为inline,那么它们可以在两个TU中定义,链接器将丢弃其中一个定义:

template<>
inline bool Foo_Helper<1>::Compare(const Foo& this_foo, const Foo& other_foo)
//^^^^
{
    return this_foo.Value() == other_foo.Value();
}

template<>
inline bool Foo_Helper<2>::Compare(const Foo& this_foo, const Foo& other_foo)
//^^^^
{
    return this_foo.Value() == other_foo.Value();
}