I have a class template Foo<T>
, deriving from FooBase
.
Foo.h:
class FooBase
{
public:
virtual ~FooBase() {}
};
template <class T>
class Foo : public FooBase
{
public:
T t;
};
Then, I have two translation units instantiating Foo with different T
's. The class used as template parameter is called T
in both translation units, but protected by an unnamed namespace. Each translation unit defines a free function.
Test1.h:
void test1();
Test1.cpp:
#include "Test1.h"
#include "Foo.h"
#include <cassert>
namespace { class T {}; }
void test1()
{
Foo<T> foo;
FooBase & base = foo;
assert(&base == &foo); // To be able to breakpoint here
}
Test2.h:
void test2();
Test2.cpp:
#include "Test2.h"
#include "Foo.h"
#include <cassert>
namespace { class T { int x; }; }
void test2()
{
Foo<T> foo;
FooBase & base = foo;
assert(&base == &foo); // To be able to breakpoint here
}
Finally, I have a main that calls both free function, and I link all three translation units.
main.cpp:
#include "Test1.h"
#include "Test2.h"
int main()
{
test1();
test2();
}
Question: Is this legal C++11 ?
I thought it should be since the name conflict is resolved by the unnamed namespace. However, I am now in doubt because:
- GDB ( v7.7.1, on Kubuntu 14.04 64bits) is really confused about this
- I have weird bugs in my real-life case which I can't track down
GDB
GDB issues those warnings on test2():
can't find linker symbol for virtual table for `FooBase' value
can't find linker symbol for virtual table for `Foo<(anonymous namespace)::T>' value
And is not able to determine that base
is actually of dynamic type Foo
and therefore inspect its member t
. Also, instead of the nice
<vtable for Foo<(anonymous namespace)::T>+16>
which I get on test1, I get the following on test2:
<_ZTV3FooIN12_GLOBAL__N_11TEE+16>
AND even much much worse, when inspecting foo.t
on test1, it finds the member foo.t.x
which should only exist in test2!
See below for screenshots within QtCreator:
All above issues are resolved if I name the template parameter T1
in Test1.cpp and T2
in Test2.cpp.
Despite GDB confusion, on all variants I tried around this minimal example, the program always seems to behave correctly (GCC 4.8.2). For instance printing sizeof(T) via a virtual method called from base correctly returns 1
and 4
for test1 and test2 respectively (while it prints 1
and 1
if I remove the unnamed namespace, due to the actual name conflict, which I know makes the code not legal C++).
Real-life case
On my real-life case, I have a segfault that:
- always occurs with "same name in global scope" (obviously)
- occurs unpredictably with "same name under unnamed namespace"
- never occurred with manually assigned unique names
I don't know if it's because assigning unique names manually fix the issue (could it, since they were already in unnamed namespace??), or if my code is still broken somewhere else and I'm just "lucky" (i.e., a hidden undefined behavior, which is very scary). I've spent two days trying to reduce to a minimal example that still crashes this way, but failed. I only managed to get minimal examples that work, or my actual code that crashes sometimes.