From here:
struct piecewise_construct_t {}; constexpr piecewise_construct_t piecewise_construct = {}; const int magic_number = 42; inline std::tuple<int> make_magic() { return std::tuple<int>( piecewise_construct, magic_number ); }
This function violates the ODR ([basic.def.odr] §3.2/6 ) twice because neither of the constructor 2 arguments receives an lvalue-to-rvalue conversion. They are therefore passed by address, but the address depends on the TU because const (and constexpr) implies internal linkage.
I initially thought it did, but the problem is that magic_number
has internal linkage. Since it has internal linkage, wouldn't it essentially treat magic_number
as if they were different variables in different translation units, and therefore not as multiple definitions of the same variable? Can someone specify this by using quotes of the latest working draft of the C++ standard?
The problem is with make_magic
. [basic.def.odr]/p6:
There can be more than one definition of ... inline function with external linkage (7.1.2) ... in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named
D
defined in more than one translation unit, then
- each definition of
D
shall consist of the same sequence of tokens; and- in each definition of
D
, corresponding names, looked up according to 3.4, shall refer to an entity defined within the definition ofD
, or shall refer to the same entity, after overload resolution (13.3) and after matching of partial template specialization (14.8.3), except that a name can refer to a non-volatileconst
object with internal or no linkage if the object has the same literal type in all definitions ofD
, and the object is initialized with a constant expression (5.20), and the object is not odr-used, and the object has the same value in all definitions ofD
; and- [...]
Because piecewise_construct
and magic_number
have internal linkage, when the inline function make_magic
is defined in multiple translation units, the names piecewise_construct
and magic_number
refer to different entities - TU 1's make_magic
will refer to TU 1's piecewise_construct
and magic_number
, and TU 2's make_magic
will refer to TU 2's piecewise_construct
and magic_number
. Since the constructor of tuple
at issue takes the arguments by reference, no lvalue-to-rvalue conversion is performed, the objects are odr-used, and the exception in the second bullet doesn't apply, and you have an ODR violation.
(Incidentally, std::tuple
doesn't have a piecewise_construct
constructor, and in any event such a constructor would presumably take tuples as arguments rather than a plain int
, but that's orthogonal to the point the paper is trying to make.)
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