2017-02-02 26 views
6

假設我有一個函數只接受一個類型模板參數,我不能改變它的定義/實現。打開一個類型列表

template < typename T > 
void do_it(); 

現在我有一個類型串定義的常用方式,也無法改變,要麼:

template< typename ...Ts > 
struct typelist; 

我想實現一個功能接受一個類型串,並在運行do_it()每一種類型:

template< typename List > 
void do_them(); 

我現在發現了,直到」唯一的解決辦法是:

template< typename T > 
void do_them_impl() 
{ 
    do_it<T>(); 
} 

template< typename T, typename Ts...> 
void do_them_impl() 
{ 
    do_it<T>(); 
    do_them_impl<Ts...>(); 
} 

template< template < typename...> class List, typename ...Ts > 
void do_them_extract(List<Ts...>&&) 
{ 
    do_them_impl<Ts>(); 
} 

template< typename List > 
void do_them() 
{ 
    do_them_impl(List{}); 
} 

但是,這需要4(!)函數爲每個案例我想創建一個do_them函數。我將需要其中的幾個,我不想爲每個函數編寫四個函數。我錯過了什麼嗎?

C++ 14也歡迎,C++ 17解決方案也是如此,但標記爲這樣。

回答

7

在C++中14,你可以使用一些可怕的惡作劇引入有效擴展包方面:

template< template < typename...> class List, typename ...Ts > 
void do_them_impl(List<Ts...>&&) 
{ 
    (void)std::initializer_list<int> { 
     (do_it<Ts>(), 0)... 
    }; 
} 

template< typename List > 
void do_them() 
{ 
    do_them_impl(List{}); 
} 

這可以讓你避免重複模板實例,一般比較昂貴的。

Live Demo


在C++ 17可以使用fold expressions

template< template < typename...> class List, typename ...Ts > 
void do_them_impl(List<Ts...>&&) 
{  
    (do_it<Ts>(), ...); 
} 

template< typename List > 
void do_them() 
{ 
    do_them_impl(List{}); 
} 

Live Demo

+0

太快了! C++ 14 - 是否有可能避免std :: initializer_list? (我編碼沒有STL,各種原因)。 C++ 17的版本 - 上帝,我不能等待這在Visual Studio中支持-_- –

+1

@KornelKisielewicz是的,你可以使用一個整數數組或類似的東西:'int _ [] = {0,(do_it (),0)...};'。前0是爲了避免0大小的數組,在C++中無效。 – skypjack

+1

@skypjack謝謝,這工作! –

0

這裏是一個解決方案,它利用了C++ 14的通用Lambda表達式:

template <typename T> 
struct type_ { using type = T; }; 

template <typename Type> 
using type = typename Type::type; 

template <typename List> 
struct map_; 

template <template <typename...> typename Container, typename... Ts> 
struct map_<Container<Ts...>> 
{ 
    template <typename Fun> 
     void operator()(Fun&& fun) 
     { 
      (void)((int[sizeof...(Ts)]){(fun(type_<Ts>{}), 0)...}); 
     } 
}; 

template <typename List> 
auto map = map_<List>{}; 

然後爲每個功能

#include <iostream> 
#include <cxxabi.h> 
#include <typeinfo> 

template <typename T> 
const char * type_name() 
{ 
     return abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, nullptr); 
} 

template <typename T> 
void do_it() 
{ 
    std::cout << type_name<T>() << std::endl; 
} 

你可以寫:

template <typename List> 
void do_them() 
{ 
    map<List>([](auto v){ do_it<type<decltype(v)>>(); }); 
} 

template <typename... Ts> 
struct typelist {}; 

int main() 
{ 
    do_them<typelist<int, char, bool>>(); 
    return 0; 
} 

與-O3編譯給出了相同的組件,如果我們簡單地稱爲do_it<int>do_it<char>do_it<bool>連續。

相關問題