对 ISO C++ 标准中 std::tuple 的默认构造函数描述感到困惑
Confused by default constructor description of std::tuple in the ISO C++ Standard
标准说std::tuple
具有以下成员函数
constexpr tuple();
explicit tuple(const Types&...);
有人可以解释一下std::tuple<>
应该会发生什么吗?
我想标准中给出的定义应该是伪代码。标准中的许多定义就是这种情况;它包含几个口头给出的要求,但只能通过enable_if
这样的技巧来满足。这似乎是一个例子,其中类似C++伪代码符号在尝试实例化这样一个空元组时实际上会导致非法C++(或者它可能只是一个遗漏)。
stdlibc++ 和 libc++ 都有针对零元素元组的明确专用化。例如,在 stdlibc++ 中:
// Explicit specialization, zero-element tuple.
template<>
class tuple<>
{
public:
void swap(tuple&) noexcept { /* no-op */ }
};
使用隐式定义的明确默认构造函数。
Libc++ 没有显式声明无参数默认构造函数。据推测,模板化构造函数随后被选为非空元组的默认构造函数。
有趣的是,这两个库在空元组具有哪些成员方面存在分歧。例如,以下内容使用 libc++ 编译,但不使用 libstdc++ 编译:
#include <tuple>
#include <memory>
int main() {
std::tuple<> t(std::allocator_arg, std::allocator<int>());
}
这是标准中的一个小错误。显然,当Types
参数包为空时,两个构造函数调用是等效的,不能重载(请参阅 C++11 第 13 节)。(进一步注意,使用 Types
的构造函数也不是成员模板 - 如果是,那么它将是合法的重载。
换句话说,此代码不会编译:
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 节(关系运算符)中确实允许这样做,"对于任何两个零长度元组,[...]"。哎呀!:-)
乍一看,歧义只在调用它的位置很重要,然后你有正常的重载分辨率。
- "error: no matching function for call to"构造函数错误
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 选择要调用的构造函数
- 如何委托派生类使用其父构造函数?
- 构造函数正在调用一个使用当前类类型的函数
- 没有用于初始化C++中的变量模板的匹配构造函数
- 初始化具有非默认构造函数的std::数组项的更好方法
- 当从函数参数中的临时值调用复制构造函数时
- 在c++构造函数中使用随机字符串生成器
- 一对向量构造函数:初始值设定项列表与显式构造
- 从构造函数抛出异常时如何克服内存泄漏
- 我不明白为什么我声明一个空的内部结构并将其传递给构造函数
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 具有默认模板类型的默认构造函数的类型推导
- 请描述一下在 c++ 中在此类中定义构造函数的方式?
- 具有POSIX文件描述符对象的C 复制构造函数
- 对 ISO C++ 标准中 std::tuple 的默认构造函数描述感到困惑