C++ 从std::tuple派生的类的直接初始化失败,而它对std::pair有效
有时,我希望通过实际类使用更改我定义的类型 例如,我在此提供了一个示例,说明如何以与类型相同的方式使用结构:C++ 从std::tuple派生的类的直接初始化失败,而它对std::pair有效,c++,C++,有时,我希望通过实际类使用更改我定义的类型 例如,我在此提供了一个示例,说明如何以与类型相同的方式使用结构: using t_int_pair = std::pair< int, int >; struct s_int_pair : public std::pair< int, int > { using std::pair< int, int >::pair; // inherit ctor }; void foo() { auto [a1
using t_int_pair = std::pair< int, int >;
struct s_int_pair : public std::pair< int, int >
{
using std::pair< int, int >::pair; // inherit ctor
};
void foo()
{
auto [a1, a2] = t_int_pair{ 0, 0 };
auto [b1, b2] = s_int_pair{ 0, 0 };
// ...
}
使用t_int_pair=std::pair;
结构s_int_pair:public std::pair
{
使用std::pair::pair;//继承
};
void foo()
{
auto[a1,a2]=t_int_对{0,0};
auto[b1,b2]=s_int_对{0,0};
// ...
}
这个很好用
但是:出于任何原因,相同的代码不适用于std::tuple,即,这会产生编译错误:
using t_int_triple = std::tuple< int, int, int >;
struct s_int_triple : public std::tuple< int, int, int >
{
using std::tuple< int, int, int >::tuple; // inherit ctor
};
void bar()
{
auto [a1, a2, a3] = t_int_triple{ 0, 0, 0 };
auto [b1, b2, b3] = s_int_triple{ 0, 0, 0 }; // ERROR: cannot decompose class type 'std::_Tuple_impl<0, int, int>'
// ...
}
使用t_int_triple=std::tuple;
结构s_int_triple:public std::tuple
{
使用std::tuple::tuple;//继承
};
空条()
{
auto[a1,a2,a3]=t_int_三元组{0,0,0};
auto[b1,b2,b3]=s_int_triple{0,0,0};//错误:无法分解类类型'std::\u Tuple\u impl'
// ...
}
有人知道为什么会这样吗
有办法解决这个问题吗
我用clang、gcc和msvc在编译器浏览器上测试了这一点
感谢您的帮助
问候,
ZoppoPair是包含公共成员的聚合,而tuple则不是 您的继承自对正在使用聚合结构化绑定 Tuple使用Tuple机制。有些元组机制不能与继承一起工作,这是有充分理由的 因此,您需要专门化
std::tuple\u size
以公开tuple大小
struct s_int_triple : public std::tuple< int, int, int >
{
using std::tuple< int, int, int >::tuple; // inherit ctor
};
namespace std{
template<>
class tuple_size<::s_int_tuple>:public std::integral_constant<std::size_t, 3>{};
template< std::size_t I >
class tuple_element<I,::s_int_tuple>:public tuple_element<I, std::tuple<int,int,int>>{};
}
struct s_int_triple:public std::tuple
{
使用std::tuple::tuple;//继承
};
名称空间标准{
模板
类元组大小:public std::integral_常量{};
模板
类tuple_元素:公共tuple_元素{};
}
结构化绑定应该可以工作
是的,这很糟糕。我从将指令分成两部分开始(使用旧式初始化绕过与
std::initailizer\u列表相关的任何问题,如果有的话):
编译器错误为:
main.cpp:27:10: error: cannot decompose class type ‘std::_Tuple_impl<1, int, int>’: its base classes ‘std::_Head_base<2, int, false>’ and ‘std::_Head_base<1, int, false>’ have non-static data members
27 | auto [b1, b2, b3] = s;
| ^~~~~~~~~~~~
宾果!这是一个非静态数据成员
现在是找到结构化绑定分解的适当规则的时候了。我们去那里,直接到“案例3”:
E的每个非静态数据成员必须是E的直接成员或与E的相同基类,并且当命名为E.name时,必须在结构化绑定的上下文中格式良好。E可能没有匿名工会成员。标识符的数量必须等于非静态数据成员的数量
这里我们有了答案:从std::tuple
派生的类也继承了其他几个类,其中一些类定义了非静态成员
这一现象的简单例子:
struct A
{
int x;
};
struct B: public A
{
int y;
};
int main()
{
B obj;
auto [a, b] = obj;
}
导致
main2.cpp:14:8: error: cannot decompose class type ‘B’: both it and its base class ‘A’ have non-static data members
所以现在我们遇到了一个真正的难题:如果std::tuple
继承自不同的类,并且每个类都定义了一个非静态成员,那么为什么我们可以对tuple使用结构化绑定呢?我们回到cppreference,看到std::tuple
是上述情况3的一个例外。编译器必须以自己特殊的方式处理标准元组和类似类。换句话说,std::tuple
和类似tuple的类由案例2处理,但任何其他类或结构都由限制性更大(非常普遍)的案例3处理
因此,要使您的程序编译,您必须使您的类“类似元组”,如上面引用的源代码所述。我完全不知道这是否可能——我想这应该单独问一个问题。如何做到这一点在@yakk adam nevraumont的回答中进行了描述不,初始化工作正常,失败的是结构化绑定。这是有原因的。我很惊讶从std对继承允许结构化分解工作。也许是公众成员?这可能就是为什么。(std::get
自动工作,因为类有std::tuple
作为基本情况,对吗?)@user2是的,重载解析考虑基本情况,而模板专门化不考虑。非常感谢。。。但我认为我不会在STD命名空间中实现某些东西(AFAIK C++标准不允许它)。因此,我想我会咬紧牙关,实现一个函数,在用结构替换我的类型之后,在它不编译的任何地方使用它。@zoppo你特别允许为依赖于你的类型的类型指定某些特征,这是明确允许的,也是设计允许的。这是你应该怎么做的。非常感谢你提供的详细信息,现在我明白为什么它不能工作了。
struct A
{
int x;
};
struct B: public A
{
int y;
};
int main()
{
B obj;
auto [a, b] = obj;
}
main2.cpp:14:8: error: cannot decompose class type ‘B’: both it and its base class ‘A’ have non-static data members