为什么“std::tuple”仍然没有 move-from-elements ctor?
很久以前,我遇到了一个非常像这样的问题:
std::tuple default具有可移动构造元素的构造函数
C++ 正在高速发展和改进,但代码的微小变化仍然让程序员感到困扰。我测试了添加 SFINAE 选择的 ctor 来精确匹配 move-from-elements ctor,然后将问题解决。 现在,闪回让我再次想到这个问题。 std::tuple
仅声明 26 (=13*2) 构造函数。我想知道为什么它仍然缺少一个元素的精确匹配移动?配对<2,15>定义元素的精确匹配副本。这对击败了对<3,16>。重载(通用参考列表中的通用)。对方的举动似乎并不那么困难。随着概念的最终发布,SFINAE 变得更加简单:
template<typename ... Types>
tuple<Types ...>::tuple(Types&&... args)
requires(!(is_lvalue_reference_v<Types>&&...&&true));
template<typename Alloc, typename ... Types>
tuple<Types ...>::tuple( std::allocator_arg_t, const Alloc&, Types&&... args)
requires(!(is_lvalue_reference_v<Types>&&...&&true));
SFINAE 只是防止复制元素对应项的重复定义,以防所有元素都是右值引用;否则 - 如果至少存在一个值或右值引用元素 - 一对新的构造函数将可用。是否还有其他具体原因阻止声明这对构造函数?
下面是举例说明这一点的片段:
struct A{
A()=default;
A(A&&){endl(std::cout<<"A(A&&)");};
A(A const&){endl(std::cout<<"A(A const&)");};
};
struct B{
B()=default;
B(B&&){endl(std::cout<<"B(B&&)");};
B(B const&){endl(std::cout<<"B(B const&)");};
};
struct C{
C()=default;
C(C&&){endl(std::cout<<"C(C&&)");};
C(C const&){endl(std::cout<<"C(C const&)");};
};
std::tuple<A,B,C> abc={{},{},{}};
输出是类的复制因子的签名。因为非模板化 ctor#2 优于 ctor#3。现在,如果类的任一复制因子被注释掉(=delete
d),则代码将无法编译;因为 ctor#3 应该是显式的
。虽然建议的新构造函数应该只是有条件地显式
(如果任一元素是显式可移动的)。
Long while ago I faced a question very much like this one:
std::tuple default constructor with move-constructable element
C++ is evolving and improving at a high rate, but minor changes to code still bite a programmers toes. I tested adding a SFINAE opted ctor for exact match move-from-elements ctor and just put the problem away.
Now a flashback took me to the problem again.std::tuple
just declares 26 (=13*2) constructors. I wonder why it is still lacking one for exact match move from elements? The pair <2,15> define exact match copy from elements. This pair defeats the pair<3,16> overloads (generic make from universal reference list). A move from counterpart does not seem that difficult. SFINAE has become a lot simpler with concepts finally shipping:
template<typename ... Types>
tuple<Types ...>::tuple(Types&&... args)
requires(!(is_lvalue_reference_v<Types>&&...&&true));
template<typename Alloc, typename ... Types>
tuple<Types ...>::tuple( std::allocator_arg_t, const Alloc&, Types&&... args)
requires(!(is_lvalue_reference_v<Types>&&...&&true));
The SFINAE just prevents a duplicate definition for copy-from-elements counterparts, in case all elements are rvalue references; otherwise - if at least one value or rvalue reference element exists - a new pair of constructors will be available. Has there been any other specific reason preventing this pair of constructors from being declared?
Here is the snippet that exemplifies the point:
struct A{
A()=default;
A(A&&){endl(std::cout<<"A(A&&)");};
A(A const&){endl(std::cout<<"A(A const&)");};
};
struct B{
B()=default;
B(B&&){endl(std::cout<<"B(B&&)");};
B(B const&){endl(std::cout<<"B(B const&)");};
};
struct C{
C()=default;
C(C&&){endl(std::cout<<"C(C&&)");};
C(C const&){endl(std::cout<<"C(C const&)");};
};
std::tuple<A,B,C> abc={{},{},{}};
The output is the signature of copy ctors of the classes. Because none-templated ctor#2 is prefered over ctor#3. Now if either of the copy ctors of classes is commented out(=delete
d), the code just fails to compile; because ctor#3 is explicit
as it should be. While the proposed new constructors should be only conditionally explicit
(if either element is explicitly moveable).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论