Confused by default constructor description of std::tuple in the ISO C++ Standard

后端 未结 3 1729
孤独总比滥情好
孤独总比滥情好 2021-01-17 08:38

The Standard says that std::tuple has the following member functions

constexpr tuple();
explicit tuple(const Types&...);

C

3条回答
  •  无人共我
    2021-01-17 09:06

    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 
    struct Test
    {
      constexpr Test() {}
      explicit Test(Types const&...) { /* etc. */ }
    };
    
    int main()
    {
      Test<> a;
      Test 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::Test(const Types& ...) [with Types = {}]’ cannot be overloaded
       explicit Test(Types const&...) { /* etc. */ }
                ^
    tt.cxx:4:13: error: with ‘constexpr Test::Test() [with Types = {}]’
       constexpr Test() {}
                 ^
    

    This can be fixed by using partial specialization:

    template 
    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 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! :-)

提交回复
热议问题