混乱同时从std :: tuple派生,不能处理std :: get [英] Confusion while deriving from std::tuple, can not handle std::get

查看:176
本文介绍了混乱同时从std :: tuple派生,不能处理std :: get的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的基本想法是从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 ...){};

使用index_sequence = std :: index_sequence_for< T ...> ;;
};

现在我尝试使用下面的代码:

 使用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>>

使用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)
{
//如果TypeContainer带有
//空元素,以下行会导致错误。空元素在std: :get< 1>其中
//不在这里访问!
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); //<<此行引发错误

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)编译 code>我得到以下错误:


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


有人可以解释为什么与 std :: get 相关联的空 TypeContainer 在这个问题?



编辑:
其他信息:



b
$ b

  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编译。 / p>

有点难以理解...



Edit2:
浏览错误列表长的一个:-))我发现:


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


似乎在libg ++中有人从任何元组类型派生多次,破碎的图书馆。搜索此主题引导我:空嵌套元组错误



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

解决方案

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

 模板< 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& 。&>(v));
}
template< std :: size_t I,typename ... T>
decltype(auto)get(TypeContainer< T ...> const& v)
{
return std :: get< I>(static_cast< std :: tuple& 。> const&>(v));
}

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



我想,我不知道,这是因为gcc有 EBO - 空基本优化 - 以其元组实现。什么是确切的原因,是很难猜到。您可以考虑在 gcc bugzilla 中报告此问题。






BTW,从STD类派生是不好的习惯。如果你从compisition开始,不是继承,那么你需要提供自己的 get 函数,你不会观察到这个错误,节省了很多时间。


My basic idea was to derive my own class from std::tuple to get some helper types inside like this:

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:

error: no matching function for call to '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?

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. This is a bit mysterious because I remember that the constructor of the tuple is indeed explicit. Why this works with 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.

A bit hard to understand...

Edit2: Digging through the error lists ( a long one :-) ) I found:

/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| note: 'std::tuple<_Elements ...>' is an ambiguous base class of 'TypeContainer<TypeContainer<float, int>, TypeContainer<>, TypeContainer<int> >' || 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. 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:

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. 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. What are exact reason it is quite hard to guess. You might consider to report this in gcc bugzilla.


BTW, it is not good habit to derive from STD classes. 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.

这篇关于混乱同时从std :: tuple派生,不能处理std :: get的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆