2013-10-10 159 views
3

是的。獲取variadic模板variadic模板參數variadic參數

比方說,我有一個持有的typedef一個簡單的可變參數的結構:

template<typename... TArgs> struct TupleTypeHolder { 
    using TupleType = std::tuple<TArgs*...>; 
}; 

我想通過TupleTypeHolder<something>作爲模板參數到另一個類,並獲得該類型定義。

我所有的嘗試都不編譯。

// None of these is valid 
template<template<typename...> class TTupleTypeHolder> struct TupleMaker { 
    using MyTupleType = TTupleTypeHolder::TupleType; // Not valid 
    using MyTupleType = typename TTupleTypeHolder::TupleType; // Not valid 
}; 

template<template<typename... A> class TTupleTypeHolder> struct TupleMaker2 { 
    // A is not a valid name here 
    using MyTupleType = TTupleTypeHolder<A...>::TupleType; // Not valid 
    using MyTupleType = typename TTupleTypeHolder<A...>::TupleType; // Not valid 
}; 

有沒有使用可變參數模板參數的方式(在這種情況下,TupleTypeHolderTArgs...)從使用上述類爲模板,可變參數模板參數的類的可變參數模板類的?


用例:

template<typename... TArgs> struct TupleTypeHolder { 
    using TupleType = std::tuple<TArgs*...>; 
}; 

template<typename... TArgs> static int getSomeValue() { ... } 

template<??? T1, ??? T2> class TupleMaker 
{ 
    std::pair<int, int> someValues; 

    using TupleType1 = T1::TupleType; 
    using TupleType2 = T2::TupleType; 

    TupleMaker() : someValues{getSomeValue<T1's TArgs...>(), 
          getSomeValue<T2's TArgs...>()} { } 
}; 

class MyTupleMaker : TupleMaker<TupleTypeHolder<int, char>, 
           TupleTypeHolder<int, float>> 
{ }; 

MyTupleMaker::TupleType1 tuple1{new int(1), new char('a')}; 
MyTupleMaker::TupleType2 tuple1{new int(35), new float(12.f)}; 
+2

1)'TTupleTypeHolder'是一個模板,而不是一個類型。 2)你不能訪問'A'(你傳遞一個模板,沒有參數,所以沒有任何參數可以推斷出來)。 – dyp

+0

在你的代碼中'A'沒有意義。這不是一個參數。這只是一個名字,沒有任何意義。它更像是模板模板參數的*簽名*的一部分。 – Nawaz

+0

請顯示使用示例(「TupleMaker」的預期用法示例)。 – dyp

回答

5

工作使用示例:

#include <tuple> 

template<typename... TArgs> struct TupleTypeHolder { 
    using TupleType = std::tuple<TArgs*...>; 
}; 

template<typename... TArgs> static int getSomeValue() { return 42; } 

// primary template: 
template<class T1, class T2> 
struct TupleMaker; 

// partial specialization: 
template<template<class...> class TT1, template<class...> class TT2, 
     class... T1, class... T2> 
struct TupleMaker < TT1<T1...>, TT2<T2...> > 
{ 
    std::pair<int, int> someValues; 

    using TupleType1 = typename TT1<T1...>::TupleType; 
    using TupleType2 = typename TT2<T2...>::TupleType; 

    TupleMaker() : someValues{getSomeValue<T1...>(), 
           getSomeValue<T2...>()} { } 
}; 

struct MyTupleMaker : TupleMaker<TupleTypeHolder<int, char>, 
           TupleTypeHolder<int, float>> 
{ }; 

MyTupleMaker::TupleType1 tuple1{new int(1), new char('a')}; 
MyTupleMaker::TupleType2 tuple2{new int(35), new float(12.f)}; 

int main() {} 

主要模板需要兩個類型,你傳遞的類型。 TupleTypeHolder<int, char>是一種類型,是模板的專業化,而不是模板本身。模板模板參數但是採取模板作爲參數(不種),如:

template<template<class...> class Foo> 
struct Bar 
{ 
    using type = Foo<int, double, char>; 
}; 

Bar<std::tuple> b; // note: no template arguments for `std::tuple`! 

隨着局部特殊化,你可以在模板特分成模板和參數,這就是上述的工作原理。

+0

太棒了,謝謝。 –

+0

很好的答案!我甚至都不知道你可以做這樣的技巧,像傳遞兩個可變參數類型的包含部分模板特化一樣,因爲在主模板類型中有一個限制,即可變參數必須在最後,編譯器不允許使用兩個包。我非常開悟! – 2013-10-10 15:00:35

+0

......但我覺得我應該已經開始認真開悟了,而是半途而廢地睡着了。 +1 –

2

模板模板參數不是真正的類型參數,是指定模板的參數。這意味着你通過一個模板,模板參數究竟是不是一個類型,是一個模板:

template<template<typename> class TPARAM> 
struct give_me_a_template 
{ 
    using param = TPARAM; //Error TPARAM is not a type, is a template. 
    using param_bool = TPARAM<bool>; //OK, thats a type 
}; 

正如你所看到的,第一別名是無效的,因爲TPARAM不是一個類型,是一個模板。但第二個是一個類型(是模板的一個實例)。

這就是說,檢查你的問題:你所謂的TupleTypeHolder可以被視爲一個可變模板類型列表。所以你的目標是使用類型列表來指定類型的元組,對吧?

您可以使用偏特提取類型串的內容:

template<typename TupleTypeHolder> 
struct tuple_maker; 

template<typename... Ts> 
struct tuple_maker<TupleTypeHolder<Ts...>> 
{ 
    using tuple_type = std::tuple<Ts...>; 
}; 

其使用的一個例子是:

using my_types = TupleTypeHolder<int,int,int>; 
using my_tuple_type = typename tuple_maker<my_types>::tuple_type; 

當然這不是正好解決您的實現,你需要將這個概念擴展到多個類型列表(如你的問題所示)。我所提供的是瞭解問題及其解決方案的指南。