修改元组元素的类型

时间:2017-09-09 13:15:07

标签: c++ stdtuple

将类型列表作为可变参数模板参数,对它们执行任意类型操作非常容易,因此可以获得修改类型的元组。例如。要使用自定义包装类包装每个元素,可以执行以下操作:

template<typename T> class Wrapper {};

template<typename ...Values>
using WrappedValues = std::tuple<Wrapper<Values>...>;

using NewTuple = WrappedValues<int, std::string, char>;
static_assert(std::is_same<NewTuple, std::tuple<Wrapper<int>, Wrapper<std::string>, Wrapper<char>>>::value, "");

如果将std :: tuple专门化为“输入”,如何做同样的事情?例如。应该放什么而不是“???”使以下代码可编译:

template<typename T> class Wrapper {};

template<typename Tuple>
using WrappedTupleElements = ???;

using NewTuple = WrappedTupleElements<std::tuple<int, std::string, char>>;
static_assert(std::is_same<NewTuple, std::tuple<Wrapper<int>, Wrapper<std::string>, Wrapper<char>>>::value, "");

我知道使用std::tuple_element和递归模板实例化访问元组元素类型的可能性,但我不知道如何将以这种方式创建的类型收集到一个元组中。

首选是纯C ++ 14答案,但也欢迎使用C ++ 17,广泛使用的TS或外部库(例如boost)的提案。

2 个答案:

答案 0 :(得分:2)

为什么不使用允许专业化的其他结构模板:

#include <string>
#include <tuple>
#include <type_traits>

template<typename T> class Wrapper {};

template<typename Tuple>
struct WrappedTupleElements;

template <class... Values>
struct WrappedTupleElements<std::tuple<Values...>> {
    using type = std::tuple<Wrapper<Values>...>;
};

int main() {
    using NewTuple = WrappedTupleElements<std::tuple<int, std::string, char>>::type; 
    static_assert(std::is_same<NewTuple, std::tuple<Wrapper<int>, Wrapper<std::string>, Wrapper<char>>>::value, "");
}

[live demo]

答案 1 :(得分:2)

一个常见的习语(例如boost mpl)是采用元函数的概念。

元函数是一个模板类,它声明一个名为result的类型,它产生在输入上应用元函数的结果类型。

#include <string>
#include <tuple>
#include <type_traits>

template<typename T> class Wrapper {};

namespace metafunction
{
    template<class MetaFunction> using result_of = typename MetaFunction::result;

    // meta-function which yields Wrapper<Element> from Element
    // type: unary metafunction
    // arg1 = the type to wrap
    // returns Wrapper<arg1>
    //
    template<class Element>
    struct apply_wrapper
    {
        using result = Wrapper<Element>;
    };

    template<class Tuple, template<class> class Function>
    struct transform_elements;

    // meta-function which takes a tuple and a unary metafunction
    // and yields a tuple of the result of applying the metafunction
    // to each element_type of the tuple.
    // type: binary metafunction
    // arg1 = the tuple of types to be wrapped
    // arg2 = the unary metafunction to apply to each element_type
    // returns tuple<result_of<arg2<element>>...> for each element in arg1

    template<class...Elements, template<class> class UnaryMetaFunction>
    struct transform_elements<std::tuple<Elements...>, UnaryMetaFunction>
    {
        template<class Arg> using function = UnaryMetaFunction<Arg>;
        using result = std::tuple
        <
            result_of<function<Elements>>...
        >;
    };
}

int main() {
    using input_type = std::tuple<int, std::string, char>;

    using namespace metafunction;

    using wrapped_tuple = result_of<transform_elements<input_type, apply_wrapper>>;

    static_assert(std::is_same<wrapped_tuple, std::tuple<Wrapper<int>, Wrapper<std::string>, Wrapper<char>>>::value, "");
}