有时,我想通过一个真正的类来更改我定义的类型。
例如,我在这里举了一个例子,如何以与类型相同的方式使用结构:
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 };
// ...
}
这工作正常。
但是:由于任何原因,相同的代码不适用于std::元组,即这会产生编译错误:
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>'
// ...
}
有人知道为什么会这样吗?
有办法解决这个问题吗?
我用clang、gcc和msvc在编译器资源管理器上测试了这个。
感谢您的帮助,
问候,
佐波
Pair是公共成员的聚合,tuple不是。
您的继承自对正在使用聚合结构化绑定。
Tuple使用Tuple机器。有些元组机制不适用于继承,这是有充分理由的。
所以你需要专门化std::tuple_size
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>>{};
}
和结构化绑定应该工作。
是的,这太糟糕了。
我从将指令分成两部分开始(使用旧风格的初始化来绕过与std::initailizer_list
相关的任何问题,如果有的话):
s_int_triple s( 0, 0, 0 );
auto [b1, b2, b3] = s;
编译器错误如下:
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;
| ^~~~~~~~~~~~
所以我得出结论,构造函数的继承不是问题,问题在于结构化绑定。当你必须查看C的标准模板库时,C是一种糟糕的语言,但在将程序加载到一个像样的IDE后,我发现在std::tuple
的gcc 10,2实现中,这个类公开继承了\u tuple\u impl
_Head _M_head_impl;
答对 了这是一个非静态数据成员。
现在是找到结构化绑定分解的适当规则的时候了。我们去https://en.cppreference.com/w/cpp/language/structured_binding然后,直奔“案例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的回答中有所描述
我不熟悉<code>std::map</code>,最近才开始使用它。 我遇到了其中一个映射的编译问题。 我有一个自定义结构,并试图用该结构类型的对象创建一个< code>CString的映射。 不幸的是,我遇到了问题
我的基本想法是从std::tuple派生我自己的类,以便在里面获得一些helper类型,如下所示: 现在我尝试使用如下代码: 线条 不能用GCC5.2.0编译,而是用GCC6.1.0编译。这有点神秘,因为我记得元组的构造函数确实是显式的。为什么这适用于GCC6.1.0?但这不是我寻找的问题:-) 另一个提示:我遇到问题的代码似乎是用Clang3.5.0编译的。
以下节目 使用当前Clang(12.0.0)编译,但不使用当前GCC(11.0.0 20201028)。使用GCC它会产生错误 根据[dcl.init.list/5]和string_view(char const*)构造函数是constepr这一事实,我假设Clang的行为就在这里。 对吗?
我不知道如何创建以下内容: 我总是得到 /usr/include/c/5.5.0/bits/stl_对。h:139:45:错误:使用已删除的函数'std::atomic::atomic(const std::atomic 我已经试过了 我知道std::atomic是不可复制的,那么你应该如何创建一对呢?难道这不可能吗?
我以前见过这样做,但我不记得如何有效地初始化已知长度的与长度相同的。这里有一个很好的例子: 我已经仔细阅读了这一页关于高级矩阵初始化的内容,但是没有明确解释执行此操作的方法。