该标准规定std::tuple
具有以下成员函数
constexpr tuple();
explicit tuple(const Types&...);
有人能解释一下std::tuple<>
会发生什么吗?
发布于 2012-07-09 04:39:17
我认为这是标准中的一个小错误。显然,当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
的定义不适用于大小为0的元组。但是,标准在20.4.2.7节(关系运算符)中确实允许这样做,“对于任何两个长度为零的元组,...”。哦!:-)
发布于 2012-07-09 04:00:59
我猜标准中给出的定义应该是伪代码。标准中的许多定义就是这种情况;它包含几个口头给出的要求,但只能通过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>());
}
发布于 2012-07-09 03:52:48
乍一看,模糊性只在被调用的地方才重要,然后你就有了正常的重载解决方案。
https://stackoverflow.com/questions/11386042
复制相似问题