从 std::tuple 派生时出现混乱,无法处理 std::get

2024-03-30

我的基本想法是从 std::tuple 派生我自己的类,以获取一些辅助类型,如下所示:

template <typename ... T>
class TypeContainer: public std::tuple<T...>
{   
    public:
        using BaseType = std::tuple<T...>;
        static const size_t Size = sizeof...(T);
        TypeContainer(T... args):std::tuple<T...>(args...){};

        using index_sequence = std::index_sequence_for<T...>;
};

现在我尝试使用如下代码:

using MyType_tuple_with_empty =         std::tuple<       std::tuple<float,int>,    std::tuple<>,    std::tuple<int>>;
using MyType_typecontainer_with_empty = TypeContainer< TypeContainer<float,int>, TypeContainer<>, TypeContainer<int>>;

using MyType_tuple_non_empty =          std::tuple<       std::tuple<float,int>,    std::tuple<int>,    std::tuple<int>>;
using MyType_typecontainer_non_empty =  TypeContainer< TypeContainer<float,int>, TypeContainer<int>, TypeContainer<int>>;

template <typename T>
void Do( const T& parms )
{
    // The following lines result in errors if TypeContainer with
    // empty element comes in. The empty element is in std::get<1> which
    // is NOT accessed here!
    std::cout << std::get<0>(std::get<0>(parms)) << " ";
    std::cout << std::get<1>(std::get<0>(parms)) << std::endl;

    std::cout << std::get<0>(std::get<2>(parms)) << std::endl;
}


int main()
{
    MyType_tuple_with_empty         p1{{ 1.2,3},{},{1}};
    Do( p1 );

    MyType_typecontainer_with_empty p2{{ 1.2,3},{},{1}};
    Do( p2 ); // << this line raise the error

    MyType_tuple_non_empty          p3{{ 1.2,3},{4},{1}};
    Do( p3 );

    MyType_typecontainer_non_empty  p4{{ 1.2,3},{4},{1}};
    Do( p4 );
}

如果我编译Do(p2)我收到以下错误:

错误:没有匹配的函数可调用 'get(const TypeContainer<TypeContainer<float, int>, TypeContainer<>, TypeContainer<int> >&)'

有人可以解释为什么存在空的吗TypeContainerstd::get会导致那个问题吗?

编辑: 附加信息:

线条

MyType_tuple_with_empty         p1{{{ 1.2,3},{},{1}}};
MyType_tuple_non_empty          p3{{ 1.2,3},{4},{1}};

不能用gcc5.2.0编译,但用gcc6.1.0编译。这有点神秘,因为我记得元组的构造函数确实是显式的。为什么这适用于 gcc6.1.0?但这不是我寻找的问题:-)

另一个提示: 我遇到问题的代码似乎是用 clang3.5.0 编译的。

有点难以理解...

编辑2: 仔细研究错误列表(很长:-))我发现:

/opt/linux-gnu_5.2.0/include/c++/5.2.0/tuple|832 列 5|注意:模板参数推导/替换失败: main.cpp|104 第 45 栏|笔记: 'std::tuple<_Elements ...>' 是 ' 的不明确基类TypeContainer<TypeContainer<float, int>, TypeContainer<>, TypeContainer<int> >' ||std::cout << std::get<0>(std::get<0>(parms)) << " ";

似乎在 libg++ 中,有人从任何元组类型中多次派生,这似乎是一个损坏的库。搜索这个主题让我发现:空嵌套元组错误 https://stackoverflow.com/questions/10999062/empty-nested-tuples-error

这真的有关系吗?相同的错误或新的错误:-)


不幸的是,您必须添加 get 函数的容器版本:

template <std::size_t I, typename ...T>
decltype(auto) get(TypeContainer<T...>&& v)
{
    return std::get<I>(static_cast<std::tuple<T...>&&>(v));
}
template <std::size_t I, typename ...T>
decltype(auto) get(TypeContainer<T...>& v)
{
    return std::get<I>(static_cast<std::tuple<T...>&>(v));
}
template <std::size_t I, typename ...T>
decltype(auto) get(TypeContainer<T...> const& v)
{
    return std::get<I>(static_cast<std::tuple<T...> const&>(v));
}

只需使用get not std::get in Do种功能。编译器能够从参数中选择命名空间。

我想,我不确定,这是因为海湾合作委员会有EBO - 空基地优化 https://stackoverflow.com/questions/15076961/common-base-class-breaks-empty-base-class-optimization-for-tuples- 在其元组中实现。具体原因是什么,很难猜测。您可以考虑在以下位置报告此情况海湾合作委员会bugzilla https://gcc.gnu.org/bugzilla/buglist.cgi?quicksearch=tuple.


顺便说一句,从 STD 类派生并不是一个好习惯。如果您从组合开始,而不是继承,那么您需要提供自己的get函数,您就不会观察到此错误,这可能会节省大量时间。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从 std::tuple 派生时出现混乱,无法处理 std::get 的相关文章