模板函数中本地派生对象的链接错误
我有一个模板化函数,它使用派生自另一个基类的本地类。当此函数在不同的编译单元中实例化时,链接器会为默认构造函数和析构函数抛出“多重定义”错误。
以下是一些给我带来麻烦的代码的精简版本。它由三个文件组成。它应该是有效的(?)C++ 代码:
ah:
struct foo {
template <typename T>
void f(const T&);
};
struct base {
virtual ~base(){};
};
template <typename T>
void foo::f(const T&) {
struct derived: public base {
// derived(){}
// virtual ~derived(){}
};
derived x;
}
a.cpp:
#include "a.h"
void fa() {
foo a;
a.f(1);
}
int main(int argc, char *argv[]){}
b.cpp:
#include "a.h"
void fb() {
foo a;
a.f(1);
}
编译此代码会生成链接器错误,因为导出的构造函数和析构函数存在两次:
$ g++ a.cpp b.cpp
/tmp/ccvPK1l5.o: In function `void foo::f<int>(int const&)::derived::derived()':
b.cpp:(.text+0x24): multiple definition of `void foo::f<int>(int const&)::derived::derived()'
/tmp/ccRb6RYO.o:a.cpp:(.text+0x36): first defined here
[...]
有趣的是,如果您手动定义派生的构造函数和析构函数派生(通过取消注释这两行),一切正常。
我的代码中是否有任何无效内容,或者是 gcc 中的错误?我尝试了 gcc 4.3 和 4.4,两者都有同样的问题。
对于我的真实代码,我通过将“派生”声明为全局类而不是 f 中的本地类来解决这种情况。但我仍然有兴趣知道出了什么问题以及原因,这样我就可以在将来避免它。
I'm having a templated function that uses a local class which is derived from another base class. When this function gets instantiated in different compilation units, the linker throws "multiple definition" errors for the default constructor and destructor.
The following is a boiled down version of some code that was causing me trouble. It consists of three files. It is meant to be valid(?) C++ code:
a.h:
struct foo {
template <typename T>
void f(const T&);
};
struct base {
virtual ~base(){};
};
template <typename T>
void foo::f(const T&) {
struct derived: public base {
// derived(){}
// virtual ~derived(){}
};
derived x;
}
a.cpp:
#include "a.h"
void fa() {
foo a;
a.f(1);
}
int main(int argc, char *argv[]){}
b.cpp:
#include "a.h"
void fb() {
foo a;
a.f(1);
}
Compiling this generates a linker error because the constructor and destructor of derived are there twice:
$ g++ a.cpp b.cpp
/tmp/ccvPK1l5.o: In function `void foo::f<int>(int const&)::derived::derived()':
b.cpp:(.text+0x24): multiple definition of `void foo::f<int>(int const&)::derived::derived()'
/tmp/ccRb6RYO.o:a.cpp:(.text+0x36): first defined here
[...]
Interestingly, if you manually define the constructor and destructor of derived (by uncommenting the two lines), everything works fine.
Is there anything invalid in my code or is it a bug in gcc? I tried gcc 4.3 and 4.4, both are having the same issue.
For my real code I solved the situation by declaring "derived" as a global class as opposed to a local one inside f. But I would still be interesting in knowing what was going wrong and why so I can avoid it in the future.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
规范说
本地类 (9.8) 的成员函数没有链接。
(C++0x 9.3p3),所以这可能是 gcc 问题。但是,它似乎在 g++4.5 中得到了解决,因为您的示例成功通过了编译并与 g++ 4.5.2 链接(带或不带注释的构造函数和析构函数):
The specification said
Member functions of a local class (9.8) have no linkage.
(C++0x 9.3p3), so this is probably a gcc problem.However, it seems to be solved in g++4.5, because you example successfully passed compilation and link with g++ 4.5.2 (with or without the constructor and destructor commented):
我认为这与模板没有任何关系,因为这通常发生在头文件中定义的函数中。例如...如果您在 ah 中创建了一个函数并且甚至没有使用它...
如果您尝试编译它。它会抱怨这是一个多重定义。修复它的方法是添加内联 ie 像
这也将修复你的情况。要记住的一点是,在头文件中定义并从多个位置包含的函数将在每个翻译单元中进行编译。这意味着当您链接时将会有多个定义。如果您不希望它成为全局函数符号,您可以像上面那样将其内联,或者可以将其设为静态。如果
将其设为静态,代码将出现在使用它的每个目标文件中。如果将其内联,它将(可能)内联到每个函数中。
I don't think this has anything to do with templates, because this often happens with functions that are defined in header files. For example... if you made a function in your a.h and didn't even use it...
f you try to compile this. It will complain about this being a multiple definition. The way to fix it is to add inline i.e. like
This will also fix your case. The point to remember is that a function defined in a header file and included from multiple places will be compiled in each translation unit. That means when you link there will be multiple definitions. If you don't want it to be a global function symbol you can make it inlined like I did above, or you can make it static. If
you make it static the code will appear in every object file that uses it. If you make it inline it will be inlined (potentially) into every function.
aselle上面所说的是一个有趣的解释,尽管示例中的多重定义不是“f”函数,而是“派生”本地类ctor和dtor。无论如何,作为替代解决方法,将“f”模板成员函数声明为内联可以解决 GCC 上的链接问题:
What aselle said above is an interesting explanation, although the multiple definition in your example is not the 'f' function, but the 'derived' local class ctor and dtor. Anyway, as an alternative workaround, declaring the 'f' template member function as inline solves the linking problem on GCC:
如果您不希望内联定义所有标头定义的函数(这并不总是最好的态度),您可以避免使用预处理器在旧编译器上进行多次包含
,或者仅
在文件顶部进行包含。我正在使用 g++ 4.6 并且您的代码通过编译而没有错误,因此升级也是个好主意。
If you do not wish to define all header-defined functions inline (it is not always the best attitude), you avoid multiple including on older compilers using preprocessor
or alternatively just
on the top of the file. I am using g++ 4.6 and your code passes compilation without errors, so upgrading is also good idea.