代码之家  ›  专栏  ›  技术社区  ›  Klaus

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

  •  10
  • Klaus  · 技术社区  · 10 年前

    我的基本想法是从std::tuple派生出我自己的类,以便在其中获得一些helper类型,如下所示:

    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> >&) '

    有人能解释为什么空 TypeContainer 与…有关 std::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-gnu5.2.0/include/c++/5.2.0/tuple|832 col 5 |注意:模板参数推导/替换失败: 主要的cpp | 104 col 45 |注:' std::tuple<_Elements ...> '是'的不明确基类 TypeContainer<TypeContainer<float, int>, TypeContainer<>, TypeContainer<int> > ' || std::cout << std::get<0>(std::get<0>(parms)) << " " ;

    似乎在libg++中,有人多次从任何元组类型派生,而该元组类型似乎是一个损坏的库。搜索此主题使我想到: Empty nested tuples error

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

    1 回复  |  直到 9 年前
        1
  •  3
  •   Community Mohan Dere    9 年前

    很遗憾,您必须添加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 std::get 在里面 Do 功能类型。编译器可以从参数中选择命名空间。

    我想,我不确定,这是因为gcc EBO - Empty Base Optimization -在其元组中实现。很难猜测确切的原因是什么。你可以考虑在 gcc bugzilla .


    顺便说一句,从STD类派生不是一个好习惯。如果你是从竞争开始的,而不是继承,那么你需要提供你自己的 收到 函数,您将不会看到此错误,这可能会节省大量时间。