The Standard says that std::tuple has the following member functions
constexpr tuple(); explicit tuple(const Types&...); Can someone please explain what is supposed to happen for std::tuple<>?
I guess the definition given in the standard is supposed to be pseudocode. That is the case with many of the definitions in the standard; it contains several requirements that are given verbally, but are satisfiable only with tricks like enable_if. This seems to be an example where the C++-like pseudocode notation can actually lead to illegal C++ when trying to instantiate such an empty tuple (or it might just be an omission).
Both stdlibc++ and libc++ have an explicit specialization for the zero-element tuple. For example, in stdlibc++:
// Explicit specialization, zero-element tuple. template<> class tuple<> { public: void swap(tuple&) noexcept { /* no-op */ } }; with an implicitly-defined unambiguous default constructor.
Libc++ does not explicitly declare the parameterless default constructor. Presumably the templated constructor is then chosen as default constructor for non-empty tuples.
Interestingly, the two libraries disagree on what members the empty tuple has. For example, the following compiles with libc++, but not with libstdc++:
#include <tuple> #include <memory> int main() { std::tuple<> t(std::allocator_arg, std::allocator<int>()); } tuple<>() in a rather obscure (for me) example of std::scoped_allocator_traits::construct() at § 20.12.4-12. Anyway, I would expect it added in a future revision of the library, although I cannot find any defect report in the C++ Standard Library Issues List.I believe this is a minor error in the standard. Clearly, when the Types parameter pack is empty, the two constructor calls are equivalent and cannot be overloaded (see C++11 section 13). (Further note that the constructor using Types is not a member template either --if it was, then it would be a legal overload.).
In other words, this code will not compile:
template <typename... Types> struct Test { constexpr Test() {} explicit Test(Types const&...) { /* etc. */ } }; int main() { Test<> a; Test<int> b; } e.g., a g++ v4.8 snapshot outputs:
tt.cxx: In instantiation of ‘struct Test<>’: tt.cxx:10:10: required from here tt.cxx:5:12: error: ‘Test<Types>::Test(const Types& ...) [with Types = {}]’ cannot be overloaded explicit Test(Types const&...) { /* etc. */ } ^ tt.cxx:4:13: error: with ‘constexpr Test<Types>::Test() [with Types = {}]’ constexpr Test() {} ^ This can be fixed by using partial specialization:
template <typename... Types> struct Test { constexpr Test() {} // default construct all elements explicit Test(Types const&...) { /* etc. */ } // and all other member definitions }; template <> struct Test<> { constexpr Test() {} // and any other member definitions that make sense with no types }; int main() { Test<> a; Test<int> b; } which will compile correctly.
It appears the standard wanted a constexpr default constructor was so that std::tuple<> var; could be written instead of writing std::tuple<> var(); or std::tuple<> var{}; because of the use of explicit with the other constructor. Unfortunately, its definition of std::tuple does not work for tuples of size zero. The standard does permit such in section 20.4.2.7 (relational operators) though, "For any two zero-length tuples, [...]". Oops! :-)
At first sight, the ambiguity would only matter at the point where it's called, and then you have normal overload resolution.
std::tuple<>isn't an expression. what's the question?