18

该标准说std::tuple具有以下成员功能

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

有人可以解释一下应该发生std::tuple<>什么吗?

4

3 回答 3

6

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>());
}
于 2012-07-08T20:00:59.440 回答
2

我相信这是标准中的一个小错误。显然,当Types参数包为空时,两个构造函数调用是等价的,不能重载(参见 C++11 第 13 节)。(进一步注意,构造函数 usingTypes也不是成员模板——如果是,那么它将是合法的重载。)。

换句话说,这段代码不会编译:

template <typename... Types>
struct Test
{
  constexpr Test() {}
  explicit Test(Types const&...) { /* etc. */ }
};

int main()
{
  Test<> a;
  Test<int> b;
}

例如,g++ v4.8 快照输出:

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() {}
             ^

这可以通过使用部分特化来解决:

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;
}

这将正确编译。

似乎标准需要一个constexpr默认构造函数,以便std::tuple<> var;可以编写而不是编写std::tuple<> var();或者std::tuple<> var{};因为explicit与其他构造函数一起使用。不幸的是,它的定义std::tuple不适用于大小为零的元组。但是,该标准在第 20.4.2.7 节(关系运算符)中确实允许这样做,“对于任何两个零长度元组,[...]”。哎呀!:-)

于 2012-07-08T20:39:16.743 回答
-1

乍一看,歧义只在它被调用的地方很重要,然后你就有了正常的重载解决方案。

于 2012-07-08T19:52:47.987 回答