Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is an implementation of std::tuple allowed to fail with triggering a derived-to-base conversion for empty class elements?

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++?

like image 420
Johannes Schaub - litb Avatar asked Dec 16 '12 15:12

Johannes Schaub - litb


2 Answers

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...

like image 151
Matthieu M. Avatar answered Nov 08 '22 18:11

Matthieu M.


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.

like image 39
ecatmur Avatar answered Nov 08 '22 18:11

ecatmur