2017-09-09 108 views
1

將類型列表作爲可變參數模板參數,可以非常容易地對它們執行任意類型的操作,從而獲得修改後的類型的元組。例如。包裝與定製包裝類每一個元素,一個可以這樣做:修改元組元素的類型

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, ""); 

如何做同樣的,有性病的專業化::元組「輸入」的時候?例如。應該放置什麼而不是「???」做下面的代碼可編譯:

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,廣泛使用的TSes或外部庫(如boost)的提議。

回答

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]

+0

死容易......我無法想象,我沒有想到這一點。謝謝! –

2

一個常見的成語(例如升壓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, ""); 
} 
+0

這個答案基本上利用了W.F.的答案中所描述的內容,但將其包含在更一般的解決方案中。既然你提到boost :: mpl,那麼使用它的例子不會是你的答案的好的擴展嗎? –

+0

@MariuszPlucińskiboost mpl現在看起來有點過時了。最近更容易使用的模型是boost :: hana(雖然它使用constexpr函數和對象來更簡潔地表達這個想法)。 我不確定我是否接受「剝削」的指控。如果我剽竊任何人,它是boost :: mpl的作者,但這並不意味着惡意 - 正如你所說,這個提議是爲這種事情提供「一般解決方案」的手段。 –

+0

感謝您指出boost :: hana的方向,我一定會檢查出來。關於'剝削',我可能說錯了(我很抱歉,英文不是我的第一語言)。我的意思是,這兩個答案基本上都使用相同的語言功能來訪問元組的參數包,這正是我完全忘記的那種技術,當我試圖自己解決問題時。這就是說,我喜歡描述更一般的方法的想法,所以我在寫出第一條評論之前就提出了答案。 –