简体   繁体   English

从std :: tuple派生的混乱,无法处理std :: get

[英]Confusion while deriving from std::tuple, can not handle std::get

My basic idea was to derive my own class from std::tuple to get some helper types inside like this: 我的基本想法是从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...>;
};

Now I try to use the code as follows: 现在,我尝试使用如下代码:

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 );
}

If I compile with Do(p2) I get the following error: 如果使用Do(p2)编译, Do(p2)出现以下错误:

error: no matching function for call to ' get(const TypeContainer<TypeContainer<float, int>, TypeContainer<>, TypeContainer<int> >&) ' 错误:没有匹配的函数来调用' get(const TypeContainer<TypeContainer<float, int>, TypeContainer<>, TypeContainer<int> >&) '

Can someone explain why the existence of an empty TypeContainer in connection with std::get will result in that problem? 有人可以解释为什么与std::get相关联的空TypeContainer会导致该问题吗?

Edit: Additional information: 编辑:附加信息:

The lines 线

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

can not compiled with gcc5.2.0 but with gcc6.1.0. 无法使用gcc5.2.0进行编译,而只能使用gcc6.1.0进行编译。 This is a bit mysterious because I remember that the constructor of the tuple is indeed explicit. 这有点神秘,因为我记得元组的构造函数确实是显式的。 Why this works with gcc6.1.0? 为什么这适用于gcc6.1.0? But that is not the problem I search for :-) 但这不是我搜索的问题:-)

Another hint: The code which I have problems with seems to compile with clang3.5.0. 另一个提示:我遇到问题的代码似乎可以用clang3.5.0编译。

A bit hard to understand... 有点难以理解...

Edit2: Digging through the error lists ( a long one :-) ) I found: Edit2:浏览错误列表(很长的一个:-)),我发现:

/opt/linux-gnu_5.2.0/include/c++/5.2.0/tuple|832 col 5| /opt/linux-gnu_5.2.0/include/c++/5.2.0/tuple|832 col 5 | note: template argument deduction/substitution failed: main.cpp|104 col 45| 注意:模板参数推导/替换失败:main.cpp | 104 col 45 | note: ' std::tuple<_Elements ...> ' is an ambiguous base class of ' TypeContainer<TypeContainer<float, int>, TypeContainer<>, TypeContainer<int> > ' || 注意:' std::tuple<_Elements ...> '是' TypeContainer<TypeContainer<float, int>, TypeContainer<>, TypeContainer<int> > '||的模棱两可的基类。 std::cout << std::get<0>(std::get<0>(parms)) << " " ; std::cout << std::get<0>(std::get<0>(parms)) << " " ;

Seems that in libg++ someone derives multiple times from any tuple type which seems to be a broken library. 似乎在libg ++中,有人从似乎是已损坏的库的任何元组类型派生了多次。 Searching for this topic brings me to: Empty nested tuples error 搜索该主题将使我进入: 空嵌套元组错误

Is this really related? 这真的相关吗? Same bug or a new one :-) 相同的错误或新的错误:-)

Unfortunately you have to add your container versions of get functions: 不幸的是,您必须添加容器的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));
}

And just use get not std::get in Do kind of functions. 并且只使用get not std::get in Do某种功能。 Compiler is able to select namespace from arguments. 编译器能够从参数中选择名称空间。

I guess, I am not sure, that this is because gcc has EBO - Empty Base Optimization - implemented in its tuples. 我猜,我不确定,这是因为gcc在其元组中实现了EBO-空基础优化 What are exact reason it is quite hard to guess. 什么是确切原因很难猜测。 You might consider to report this in gcc bugzilla . 您可能考虑在gcc bugzilla中报告此情况。


BTW, it is not good habit to derive from STD classes. 顺便说一句,从STD类中派生不是一个好习惯。 If you started from compisition, not inheritance, then you would need to provide your own get functions and you would not observe this error, saving probably a lot of time. 如果您是从组合而不是继承开始的,那么您将需要提供自己的get函数,并且不会观察到此错误,从而可能节省大量时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM