当前位置: 首页 > 知识库问答 >
问题:

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

龚同
2023-03-14

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

线条

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编译的。

共有1个答案

越英范
2023-03-14

不幸的是,您必须添加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));
}

只需在do类函数中使用get而不是std::get。编译器能够从参数中选择命名空间。

我想,我不确定,这是因为gcc在其元组中实现了EBO-空基优化。确切的原因是什么,很难猜测。您可以考虑在gcc Bugzilla中报告这一点。

顺便说一句,从STD类派生不是一个好习惯。如果从compisition开始,而不是从继承开始,则需要提供自己的get函数,这样就不会发现这个错误,可能会节省大量时间。

 类似资料:
  • 在godbolt.org中编译代码时,我遇到以下错误: 看起来该错误是在使用std::thread创建线程时出现的。该守则的简化版本为:

  • 有时,我想通过一个真正的类来更改我定义的类型。 例如,我在这里举了一个例子,如何以与类型相同的方式使用结构: 这工作正常。 但是:由于任何原因,相同的代码不适用于std::元组,即这会产生编译错误: 有人知道为什么会这样吗? 有办法解决这个问题吗? 我用clang、gcc和msvc在编译器资源管理器上测试了这个。 感谢您的帮助, 问候, 佐波

  • 以下代码片段适用于Visual Studio 2008,但不适用于Visual Studio 2010。 用法 我得到以下错误: 1个 如果用typedef int MyValueType替换typedef STD::tr1::tuple myvalue type,则有效。 提前感谢您。

  • 首先,我确实在谷歌上做了一个快速搜索,没有一个解释我拍摄的目的。 我的问题是如何在成员函数中访问该消息,例如(中的虚函数)?父类中没有定义或类似的函数,如果调用恰好是我要重写的函数,那么调用该函数是非常没用的。 我使用的是Visual Studio Community 2015,因此编译器特定的方法是可以的,但我更喜欢可移植的解决方案。

  • 我正在运行一个调用shell脚本的程序(用于讨论带有pid 100的sh1)。该脚本依次调用另一个脚本(用于与pid 101的讨论sh2),并等待它完成。sh2(子脚本)完成大约需要50秒。 调用sh2的方式(/bin/sh2.sh) 在等待子进程完成期间,我尝试终止sh1(使用kill-15 100)。我在sh1中有一个处理程序函数来处理此信号。但是,我观察到我的sh1(父脚本)直到子进程完成其