在类模板中创建一组映射

时间:2013-05-04 23:19:31

标签: c++ c++11

struct VectorOfMaps {
  std::tuple<std::map<std::string,double>,
              std::map<std::string,int>,
              std::map<std::string,short>
            > tuple;
};

我想将它概括为一个模板,因此上面的类将由

之类的东西产生
VectorOfMaps<3, std::string,double,
                std::string,int,
                std::string,short>

这可以做类似的事吗?

我知道我可以直接将地图类型放入模板中,但是“std::map”的重复不会被认为有点难看吗?你觉得怎么样?

(我考虑过是否可以在模板中指定std::pair类型,但我不确定这些类型是否可以直接用于创建std::map类型。)

4 个答案:

答案 0 :(得分:3)

由于您提到将对的特化传递给类模板:

template<typename... Pairs>
struct VectorOfMaps {
    std::tuple<std::map<
        typename Pairs::first_type
        , typename Pairs::second_type
    >...> tuple;
};

这实际上是使用std::pair作为类型列表 - 您也可以使用类似template<typename T, typename U> struct pair { using first_type = T; using second_type = U; };的内容。

也可以在没有一对的情况下传递类型,但这需要一些元计算。一个可能的解决方案:

// First argument is accumulator, supposed to be an empty tuple
template<typename Acc, typename... T> struct compute_tuple
{
    // Only triggered when the primary template is instantiated, which should
    // only happen if sizeof...(T) is odd -- it's possible to assert on that
    // instead, too.
    static_assert( !sizeof(Acc), "An even number of arguments is required" );
};

// Recursive case
template<typename... Acc, typename First, typename Second, typename... Rest>
struct compute_tuple<std::tuple<Acc...>, First, Second, Rest...>
: compute_tuple<std::tuple<Acc..., std::map<First, Second>>, Rest...> {};

// Terminal case
template<typename Acc>
struct compute_tuple<Acc> { using type = Acc; };

template<typename... T>
struct VectorOfMaps {
    /* 
     * You can assert that sizeof...(T) is even here; it might be more
     * helpful than an error deeper inside compute_tuple.
     */
    using tuple_type = typename compute_tuple<std::tuple<>, T...>::type;
    tuple_type tuple;
};

答案 1 :(得分:2)

first_of_pair元函数是不必要的,因为pair具有first_type和second_type成员。以下是具有可变参数模板参数的解决方案:

template<class... pairtypes>
struct VectorOfMaps
{
    std::tuple<
        std::map<
            typename pairtypes::first_type,
            typename pairtypes::second_type
        >...
    > tuple;
};

int main()
{
    VectorOfMaps<
        std::pair<int,char>,
        std::pair<char,long>
    > v;
    std::get<0>(v.tuple)[4]='a';
    std::get<1>(v.tuple)['z']=5l;
    return 0;
}

答案 2 :(得分:0)

如果您可以接受要存储的地图数量的上限,则可以使用不同n值的模板专精来实现:

template<int n, class key0, class value0, class key1 = void, class value1 = void>
struct VectorOfMaps;

template<class key0, class value0>
struct VectorOfMaps<1,key0,value0>
{
// ...
};

template<class key0, class value0, class key1, class value1>
struct VectorOfMaps<2,key0,value0,key1,value1>
{
// ...
};

更好的方法是使用可变参数模板参数。

从一对参数中,您可以使用辅助元函数提取类型:

template<class T>
struct first_of_pair;

template<class First, class Second>
struct first_of_pair<std::pair<First,Second>>
{
   typedef First type;
};

// usage in a template where T is an std::pair: typename first_of_pair<T>::type

答案 3 :(得分:0)

我认为使用std :: tuple可以提供更简单,更清晰的方式(但可能会更慢......)。

template<int pos,typename... Args> struct TypeTransformer_ {
     using ValueType =  typename std::tuple_element<1,std::tuple<Args...>>::type;
     using KeyType =  typename std::tuple_element<0,std::tuple<Args...>>::type ;
     using Type =  decltype(std::tuple_cat(std::tuple<std::map<KeyType,ValueType>>(),
                    typename TypeTransformer_<pos - 2,Args...>::Type()));
};

//Base case with two elements...
template<typename... Args>
struct TypeTransformer_<2,Args...> {
   using ValueType  = typename std::tuple_element<1,std::tuple<Args...>>::type ;
   using KeyType =  typename std::tuple_element<0,std::tuple<Args...>>::type ;
   using Type =  std::tuple<std::map<KeyType,ValueType>> ;
};

//Handling the case of an odd number of parms
template<typename... Args> struct TypeTransformer_<1,Args...> ;

//Nicer interface so we don't have to specify the number of variadic param
template <typename... Args> struct SomeStruct{
using  TupleType = typename TypeTransformer_<sizeof...(Args),Args...>::Type;
TupleType tp ;
};