我有一个使用从另一个基类派生的本地类的模板化函数。当此函数在不同的编译单元中实例化时,链接器将为默认构造函数和析构函数引发“多个定义”错误。

以下是引起我麻烦的某些代码的精简版本。它由三个文件组成。它应该是有效的(?)C++代码:

啊:

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);
}

编译它会产生链接器错误,因为derived的构造函数和析构函数存在两次:
$ 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
[...]

有趣的是,如果您手动定义了derived的构造函数和析构函数(通过取消对这两行的注释),则一切正常。

我的代码中有无效的东西吗?还是gcc中的错误?我尝试了gcc 4.3和4.4,两者都有相同的问题。

对于我的真实代码,我通过声明“派生”为全局类而不是f内部的局部类来解决这种情况。但是,我仍然会很有趣,知道出了什么问题以及为什么会这样,所以以后我可以避免它。

最佳答案

规范说的是Member functions of a local class (9.8) have no linkage.(C++ 0x 9.3p3),所以这可能是gcc问题。

但是,它似乎已在g++ 4.5中解决,因为您的示例成功通过了编译并与g++ 4.5.2链接(带有或不带有注释的构造函数和析构函数):

$ cat 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;
}

$ cat a.cpp
#include "a.h"
void fa() {
    foo a;
    a.f(1);
}

int main(int argc, char *argv[]){}

$ cat b.cpp
#include "a.h"
void fb() {
   foo a;
   a.f(1);
}

$ g++ --std=c++0x --pedantic a.cpp b.cpp -o a
$ g++ -v
Using built-in specs.
COLLECT_GCC=/usr/bin/g++
COLLECT_LTO_WRAPPER=/usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.5.2-8ubuntu4' --with-bugurl=file:///usr/share/doc/gcc-4.5/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.5 --enable-shared --enable-multiarch --with-multiarch-defaults=x86_64-linux-gnu --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib/x86_64-linux-gnu --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.5 --libdir=/usr/lib/x86_64-linux-gnu --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin --enable-gold --enable-ld=default --with-plugin-ld=ld.gold --enable-objc-gc --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)

10-07 12:30
查看更多