匹配任何类型参数的C ++可变参数模板模板参数 [英] C++ variadic template template argument that matches any kind of parameters

查看:107
本文介绍了匹配任何类型参数的C ++可变参数模板模板参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道是否可以编写一个模板函数,该函数可以将任何其他任意模板作为参数并正确匹配模板名称(即不仅仅是结果类).我所知道的是这样的:

I was wondering if it's possible to write a template function that can take any other arbitrary template as a parameter and properly match the template name (i.e. not just the resulting class). What I know to work is this:

template<template<typename ...> class TemplateT, typename... TemplateP>
void f(const TemplateT<TemplateP...>& param);

例如,将匹配f(std::vector<int>())f(std::list<int>()),但不适用于f(std::array<int, 3>()),因为第二个参数是size_t且没有类型.

Which will match for instance for f(std::vector<int>()) or f(std::list<int>()) but will not work for f(std::array<int, 3>()), as the second parameter is a size_t and no type.

现在我想一个人可以做一些疯狂的事情,例如:

Now I guess one could do something crazy like:

template<template<typename ...> class TemplateT, size... Sizes, typename... TemplateP>
void f(const TemplateT<Sizes..., TemplateP...>& param);

希望编译器正确地将TemplateP省略号或Sizes省略号导出为空.但是它不仅丑陋,而且仍然只适用于带有类型或size_t参数的模板.仍然无法匹配带有bool参数的任意模板.

Hoping that the compiler would properly derive either the TemplateP ellipsis or the Sizes ellipsis to be empty. But not only is it ugly, it also will still just work for templates that take either types or size_t parameters. It still won't match arbitrary templates for instance with bool parameters.

对于重载的方法也是如此:

Same goes for an approach with overloading:

template<template<typename ...> class TemplateT, typename... TemplateP>
void f(const TemplateT<TemplateP...>& param);

template<template<typename ...> class TemplateT, size... Sizes>
void f(const TemplateT<Sizes...>& param);

此外,如果我们想混合使用size_ttypenames,则这种方法将行不通.因此,匹配任何东西都将是这样的,其中省略号完全没有限制:

Furthermore, such approach wont' work if we would like to mix size_t and typenames. So what would be required to match anything would be something like this, where there are no constraints at all to what is allowed in the ellipsis:

template<template<...> class TemplateT, ... Anything>
void f(const TemplateT<Anything...>& param);

该语法不起作用,但是也许还有其他语法可以定义这样的内容?

That syntax doesn't work but maybe there's other syntax to define something like this?

这主要是我想知道该语言有什么用,如果您有不同的模板,其中第一个参数始终是固定的,并且您想根据返回类型和保留其他所有内容.像这样:

This is mainly me wondering what is possible in the language, thought there might actually be a use for it, if you have different templates where the first parameter is always fixed and you would like to change it based on the return type and keep everything else. Something like this:

template<
    template<typename ValueT, ...> class TemplateT,
    ... Anything,
    typename ValueT,
    typename ResultT = decltype(some_operation_on_value_t(std::declval<ValueT>())>
TemplateT<ResultT, Anything...> f(const TemplateT<ValueT, Anything...>& in);

那么,有什么方法可以使用模式匹配以完全通用的方式使这项工作呢?

So, any way to make this work in a completely generic way using pattern matching?

这并不是纯粹的思想实验,因为我被困在其中的用例是创建在容器上操作的纯函数基元,并将隐式构造不可变的结果容器.如果结果容器具有不同的数据类型,我们需要知道容器所使用的类型,那么对任何容器的唯一要求是模板的第一个参数需要为输入类型,以便可以用其他类型替换输出结果中的类型,但是代码应该忽略之后的任何模板参数,并且不关心它是类型还是值.

This is not purely a thought experiment, as the use case for this where I was stuck was to create pure functional primitives that operate on containers and will implicitly construct immutable result containers. If the result container has a different data type we need to know the type the container operates on, so the only requirement on any container would be that the first parameter of the template needs to be the input type so it can be replaced with a different output type in the result, but the code should be oblivious to any template argument coming after that and should not care whether it's a type or a value.

推荐答案

您感兴趣的构造具有可变参数模板的两个级别.

Your interesting construct has two levels with variadic templates.

  • 外部可变参数模板参数列表TemplateP& Sizes用于功能模板
  • 内部参数包作为模板模板参数TemplateT的模板参数,类模板
  • An outer variadic template parameter list TemplateP & Sizes for a function template
  • An inner parameter pack as the template parameters of your template template parameter TemplateT, a class template

首先,让我们看一下内部的TemplateT类:为什么省略号运算符不能与TemplateT< int, 2 >之类的不匹配?好吧,该标准在§14.5.3中将可变参数模板定义为

First, let's look at the inner TemplateT class: why can the ellipsis operator not not match something like TemplateT< int, 2 >? Well, the standard defines variadic templates in §14.5.3 as

template<class ... Types> struct Tuple { };
template<T ...Values> struct Tuple2 { };

其中第一种情况的模板参数包可能匹配类型,而在第二种情况中,模板参数包类型为T的值.特别是

where the template argument pack in the first case may only match types and in the second version only values of type T. In particular,

Tuple < 0 >    error;  // error, 0 is not a type!
Tuple < T, 0 > error2; // T is a type, but zero is not!
Tuple2< T >    error3; // error, T is not a value
Tuple2< T, 0 > error4; // error, T is not a value

全部格式不正确.此外,不可能退回到类似

are all malformed. Furthermore, it is not possible to fall back to something like

template<class ... Types, size_t ...Sizes> struct Tuple { };

因为§14.1.11中的标准状态:

because the standard states in §14.1.11:

如果主类模板或别名模板的模板参数是模板参数包,则它 应该是最后一个模板参数.不得遵循功能模板的模板参数包 通过另一个模板参数,除非可以从parameter-type-list推导出该模板参数 功能模板的名称或具有默认参数(14.8.2).

If a template-parameter of a primary class template or alias template is a template parameter pack, it shall be the last template-parameter. A template parameter pack of a function template shall not be followed by another template parameter unless that template parameter can be deduced from the parameter-type-list of the function template or has a default argument (14.8.2).

换句话说,对于类模板,定义中只能出现一个可变参数包.因此,上面的(双)-variadic类定义格式不正确.因为内部类总是需要这样的组合,所以不可能像您想象的那样编写一般性的东西.

In other words, for class templates only one variadic parameter pack may appear in the definition. Therefore the above (double)-variadic class definition is malformed. Because the inner class always needs such a combination, it is impossible to write something as general as you conceived.

可以挽救什么?对于外部功能模板,可以将一些碎片放在一起,但是您不喜欢它.只要可以从第一个参数包中推导出第二个参数包,就会出现两个参数包(在功能模板中).因此,

What can be rescued? For the outer function template, some shards can be put together, but you won't like it. As long as the second parameter pack can be deduced from the first, two parameter packs may appear (in a function template). Therefore, a function such as

template < typename... Args, size_t... N > void g(const std::array< Args, N > &...arr);
g(std::array< double, 3 >(), std::array< int, 5>());

允许使用

,因为可以推导整数值.当然,这必须针对每种容器类型进行专门设置​​,并且与您的想象相去甚远.

is allowed, because the integer values can be deduced. Of course, this would have to be specialized for every container type and is far from what you had imagined.

这篇关于匹配任何类型参数的C ++可变参数模板模板参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆