模板变量是否可以用作模板参数(类似于类模板)?

问题描述:

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'的概念, –

也许附加的谓词参数(自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