I have the following example code which uses a string literal as a template parameter, such that the base class template can access the string.
The code compiles, but I get a warning which I do not fully understand:
warning: ‘ns::bar::type’ has a base ‘ns::base<((const char*)(& ns::bar::name))>’ whose type uses the anonymous namespace [enabled by default]
Working example code below:
// "test.h"
#pragma once
namespace ns
{
template <char const* str>
struct base
{
const char *name() const { return str; }
};
namespace bar
{
static constexpr char name[] = "bar";
struct type : base<name> {}; // <-- this line here
}
}
// main.cpp
#include <iostream>
#include "test.h"
int main()
{
ns::bar::type f;
std::cout << f.name() << std::endl;
return 0;
}
So my questions are:
(Note this is with gcc 4.7.2)
The issue is do with the fact that static constexpr char name[] = "bar";
has internal linkage.
Any type with internal linkage defined in a header will be a different type in every file that includes the header.
This is seldom the intention - hence the warning.
The reason there is no warning for when this is done in a source file is because that type can't ever be referred to by more than one file - hence it will always be that one type.
The warning is because name
will have a different address in each source file that test.h
is included into. Because it has internal linkage (static
) each translation unit will get its own copy; they will not be unified by the linker. This means that your code is equivalent to:
template<int> struct base { ... };
static constexpr int val = some_value_different_in_every_source_file;
struct type: base<val> {};
Your code is legal as presented, but if you include test.h
in another source file then it will violate the one-definition rule:
3.2 One definition rule [basic.def.odr]
[...]
6 - There can be more than one definition of a class type [...] provided [...]: [...]
- in each definition of
D
, corresponding names [...] can refer to a const object with internal or no linkage [only] if [...] the value (but not the address) of the object is used [...]
You're using the address of an object with internal linkage in the definition of a class type, so using it in more than one translation unit is undefined behaviour.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With