2017-05-04 198 views
3

C++ 17爲我們提供了非類型模板參數的關鍵字auto。有沒有辦法將它結合到一個模板模板參數,然後可以使用模板變量作爲參數?模板變量是否可以用作模板參數(類似於類模板)?

template <template <typename> auto X> // <-- This seems to be illegal 
struct Foo 
{ 
}; 

背景:
我想要實現的type_vector類copy_if。因爲我想用所有的條件都可以作爲模板變量,一個方式來實現這將是:

template <typename Container, 
      template <typename> auto Condition> // If this were allowed 
struct copy_if; 

template <typename... Ts, 
      template <typename> auto Condition> 
struct copy_if<type_vector<Ts...>, Condition> 
{ 
    using type = decltype(
     (type_vector<>{} + ... + 
      std::conditional_t<Condition<Ts>, 
          type_vector<Ts>, 
          type_vector<>>{})); 
}; 

當然,我可以總結我的所有變量成具有值模板結構,但我寧願避免這一點。

+0

你定義type_vector? –

+0

@RichardHodges是的,'type_vector'被定義,與'operator +'相同,用於連接兩個'type_vector' – Rumburak

+0

我不太瞭解C++ 17,但在我看來,'template auto'沒有任何意義,因爲汽車只能是一個班級。例如沒有'template int'的概念, –

回答

1

也許附加的謂詞參數(自C++ 17以來可用的constexpr lambda)建立參數是否符合您的變量模板就足夠了?

#include <algorithm> 
#include <iostream> 
#include <string> 
#include <type_traits> 

template <class T> 
constexpr bool condition = true; 

template <> 
constexpr bool condition<int> = false; 


template <class T> 
struct tag { 
    using type = T; 
}; 

template <class... Ts> 
struct type_vector { 
    template <class... Ts2> 
    type_vector<Ts..., Ts2...> operator+(type_vector<Ts2...>); 
}; 

template <class... Ts, 
      class Predicate> 
auto copy_if(type_vector<Ts...>, Predicate p) 
{ 
    return decltype(
     (type_vector<>{} + ... + 
      std::conditional_t<p(tag<Ts>{}), 
          type_vector<Ts>, 
          type_vector<>>{})){}; 
}; 

int main() { 
    auto predicate = [](auto x){ return condition<typename decltype(x)::type>;}; 
    std::cout << typeid(decltype(copy_if(type_vector<int, float, double>{}, predicate))).name() << std::endl; 
} 

C++ filt的輸出:

type_vector<float, double> 

[live demo]


編輯:

採用人工標記派遣參數類型時,有情況可能被視爲如同繁瑣。如果你想避免它,還有另一種方法。這實際上是一個呼籲避免拉姆達的operator()模板,它只是進行實例化評估結果類型(這應該是等同的任何std::true_typestd::false_type):

#include <algorithm> 
#include <iostream> 
#include <string> 
#include <type_traits> 

template <class T> 
constexpr bool condition = true; 

template <> 
constexpr bool condition<int> = false; 

template <class... Ts> 
struct type_vector { 
    template <class... Ts2> 
    type_vector<Ts..., Ts2...> operator+(type_vector<Ts2...>); 
}; 

template <class... Ts, 
      class Predicate> 
auto copy_if(type_vector<Ts...>, Predicate p) 
{ 
    return decltype(
     (type_vector<>{} + ... + 
      std::conditional_t<decltype(p(std::declval<Ts>())){}, 
          type_vector<Ts>, 
          type_vector<>>{})){}; 
}; 

int main() { 
    auto predicate = [](auto x){ return std::integral_constant<bool, condition<decltype(x)>>{};}; 
    std::cout << typeid(decltype(copy_if(type_vector<int, float, double>{}, predicate))).name() << std::endl; 
} 

[live demo]

+0

不錯!我曾想過使用一個通用的lambda,但沒有考慮過'tag'類。但是,這意味着任何想使用'copy_if'的人必須處理'tag '而不是T. – Rumburak

+0

是的,它可能有點違反直覺。我會試着更多地考慮這個方法,也許別的東西會出現在我的腦海裏。 –

+0

謝謝!我可能最終會寫一個模板類,因爲在呼叫站點更容易,但你的第二個解決方案當然是一個很好的選擇。 – Rumburak

相關問題