This code does not compile with GCC4.7
struct A {};
void f(A);
struct B { B(std::tuple<A>); };
void f(B);
int main() {
f(std::make_tuple(A()));
}
Because GCC derives from A
to make use of the empty base class optimization. However that causes GCC to pick f(A)
and complain
error:
'A'
is an inaccessible base of'tuple<A>'
Is this error granted by the C++ Standard or is this simply a bug of libstdc++?
I would say no.
At the very least:
§20.4.1 [tuple.general]
1/ [...] An instantiation of tuple with two arguments is similar to an instantiation of pair with the same two arguments. See 20.3.
And yet:
#include <tuple>
struct A {};
void f(A);
struct B { B(std::tuple<A, A>); };
void f(B);
int main() {
f(std::make_tuple(A(), A()));
}
fails with:
Compilation finished with errors:
source.cpp: In function 'int main()':
source.cpp:10:30: error: 'A' is an ambiguous base of 'std::tuple<A, A>'
source.cpp:4:6: error: initializing argument 1 of 'void f(A)'
And I very much doubt this was the Standard's intent.
Still, the least one can say is that §20.4 is rather succinct...
Under clause 17 Library introduction:
17.5.2.3 Private members [objects.within.classes]
1 - Clauses 18 through 30 and Annex D do not specify the representation of classes, and intentionally omit specification of class members. An implementation may define static or non-static class members, or both, as needed to implement the semantics of the member functions specified in Clauses 18 through 30 and Annex D.
This is supported by 1.4 Implementation compliance [intro.compliance]:
3 - For classes and class templates, the library Clauses specify partial definitions. Private members (Clause 11) are not specified, but each implementation shall supply them to complete the definitions according to the description in the library Clauses.
Implementing specified semantics through inheritance is not explicitly discussed anywhere in clause 17, but it is implicitly permitted through paragraph 3 of 17.5.2.3 above:
3 - An implementation may use any technique that provides equivalent external behavior.
This is how, for example, the node-based ordered associative containers can share implementation detail (including, eventually, class members) through inheritance.
Since the external behaviour of tuple
is changed between having A
as a class member and directly inheriting it, and since this change of behaviour causes the rejection of otherwise well-formed programs (as opposed to just changing the sizeof
of a class), libstdc++ is in violation of the Standard.
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