如何访问此嵌套模板参数?

时间:2018-06-26 20:01:43

标签: templates metaprogramming variadic-templates c++17 template-meta-programming

这是我的代码:

template<
    template <typename TSEvent,
              typename ...TSEvents> typename V,
    typename... Filtered>
constexpr auto filter() {
    if constexpr(sizeof...(TSEvents) == 0) {
        return type_list<Filtered...>{};
    }
    if constexpr(is_default_constructible<TSEvent>::value) {
        return filter<<TSEvents...>, Filtered...>();
    }
    return filter<<TSEvents...>, Filtered...>();
}

但是我得到此错误,size...(TSEvents)TSEvents未声明。无论如何,我是否可以访问嵌套模板中的TSEvents

3 个答案:

答案 0 :(得分:2)

通常通过另一个间接级别,通常是我们可以专门研究的struct

例如:

namespace detail
{
    template<class...>
    struct filter_t;

    template<template<class, class...> class V, class TSEvent, class... TSEvents, class... Filtered>
    struct filter_t<V<TSEvent,TSEvents...>, Filtered...>
    {
        static constexpr auto filter() {
            return sizeof...(TSEvents);
         }
    };
} // detail

template<class... T>
constexpr auto filter()
{
    return detail::filter_t<T...>::filter();
}

template<class T, class...U>
struct type_list{};

int main()
{
    std::cout << filter<type_list<int, int, int>, int>();
}

Live Demo

答案 1 :(得分:2)

只需提供另一个选项,您就可以仅使用函数来完成此操作。

#include <iostream>
using namespace std;
template<typename...>
struct type_list{};

template < template <typename...> typename T,typename A,typename... B, typename... Filtered> 
constexpr auto filter_impl(T<A,B...>*,type_list<Filtered...>)
{

    using filtered_list = std::conditional_t<is_arithmetic<A>::value,
                        type_list<Filtered...,A>,
                        type_list<Filtered...>>;

    if constexpr (sizeof...(B) == 0)
        return filtered_list();
    else
        return filter_impl( (T<B...>*)0, filtered_list());
}

template <typename T> 
constexpr auto filter()
{
    return filter_impl( (T*)0,type_list<>());
}

struct not_arethmetic{};



int main() {
    auto b = filter< type_list<not_arethmetic,int,bool,not_arethmetic,double> >();
    static_assert(std::is_same< decltype(b) , type_list<int,bool,double>>::value);
    return 0;
}

Demo

一件事,在您的原始示例中,您的第一个if表达式将意味着不检查最终的TSEvent,因为如果可变的TSEvents ...的大小为零,它将返回最终的TSEvent,但是将有一个最后的元素检查is_default_constructible。

此外,您可能会发现this帖子对模板模板参数名称很有用。

答案 2 :(得分:1)

  

但是我得到这个错误,大小...(TSEvents),未声明TSEvents。无论如何,我是否可以在嵌套模板中访问TSEvents?

简短回答:否。

长答案:

template<
    template <typename TSEvent,
              typename ...TSEvents> typename V,
    typename... Filtered>
constexpr auto filter()

您为filter()函数设置了两个模板参数。

第一个与TSEvents可变参数列表相关的是一个模板模板参数,该参数接收一个或多个类型参数。

但是您的函数没有收到基于该模板模板的类型(具有固定的TSEvent类型和固定的TSEvents);接收模板模板。

因此测试size...(TSEvents)没有意义,因为对于filter()而言, 修复了TSEvents列表。

以另一种方式解释这一点...您可以通过这种方式调用过滤器

filter<std::tuple, short, int, long>();

询问sizeof...(TSEvents)询问多少个类型包含std::tuple,其中std::tuple仅是类型的容器,而没有包含的类型。

如果您想在filter()函数中执行某种操作,则需要一个 type 模板参数,而不是template-template参数。

使用类(请参阅AndyG的答案)更为简单,您可以在其中使用部分专业化(对于不能使用的函数),也可以在函数接收到可以推论出类型的参数时使用函数。

假设您的filter()收到了V<SomeTypes...>类型的对象和std::tuple<Filtered...>类型的对象,则可以编写以下内容(警告:未经测试的代码)

template<
    template <typename ...> typename V,
    typename TSEvent, typename ... TSEvents, typename... Filtered>
constexpr auto filter (V<TSEvent, TSEvents...> const & v,
                       std::tuple<Filtered...> const & t) {
   /* some code where you can use also TSEvent and TSEvents... */
}

通过这种方式从TSEvent推论得出TSEvents...v