C++ C++;匹配任何类型参数的可变模板参数

C++ C++;匹配任何类型参数的可变模板参数,c++,templates,c++11,variadic-templates,template-templates,C++,Templates,C++11,Variadic Templates,Template Templates,我想知道是否可以编写一个模板函数,该函数可以将任何其他任意模板作为参数,并正确匹配模板名称(即,不只是结果类)。我所知道的工作是: template<template<typename ...> class TemplateT, typename... TemplateP> void f(const TemplateT<TemplateP...>& param); 希望编译器能够正确地将TemplateP省略号或size省略号派生为空。但它不仅难看,

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

template<template<typename ...> class TemplateT, typename... TemplateP>
void f(const TemplateT<TemplateP...>& param);
希望编译器能够正确地将
TemplateP
省略号或
size
省略号派生为空。但它不仅难看,而且只适用于采用类型或
size\t
参数的模板。它仍然不会匹配任意模板,例如带有
bool
参数的模板

重载方法也是如此:

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);
这种语法不起作用,但可能还有其他语法来定义类似的东西

这主要是我在想,如果您有不同的模板,其中第一个参数总是固定的,并且您希望根据返回类型更改它,并保留所有其他内容,那么在语言中可能会有什么用途,我想知道。大概是这样的:

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);
模板<
模板类TemplateT,
... 任何东西
typename ValueT,
typename ResultT=decltype(对值的某些操作(std::declval())>
模板f(常量模板和输入);
那么,有没有办法通过模式匹配以一种完全通用的方式实现这一点


这不是一个纯粹的思想实验,因为我遇到的这个用例是创建在容器上操作的纯函数原语,并隐式地构造不可变的结果容器。如果结果容器有不同的数据类型,我们需要知道容器操作的类型,所以对任何ntainer应该是模板的第一个参数必须是输入类型,以便可以在结果中用不同的输出类型替换它,但是代码应该忽略其后的任何模板参数,并且不应该关心它是类型还是值。

必须有一个重新绑定容器类型的元函数。 因为您不能仅替换第一个模板参数:

vector<int, allocator<int> > input;
vector<double, allocator<int> > just_replaced;
vector<double, allocator<double> > properly_rebound;

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

  • 函数模板的外部可变模板参数列表
    TemplateP
    大小
  • 一个内部参数包作为模板模板参数
    TemplateT
    ,一个类模板的模板参数
首先,让我们看一下内部的
TemplateT
类:为什么省略号运算符不能与
TemplateT
之类的内容匹配?好吧,标准在§14.5.3中将可变模板定义为

template<class ... Types> struct Tuple { };
template<T ...Values> struct Tuple2 { };
都是畸形的。此外,不可能回到类似

template<class ... Types, size_t ...Sizes> struct Tuple { };
模板结构元组{};
因为标准在§14.1.11中规定:

如果主类模板或别名模板的模板参数是模板参数包,则 应为最后一个模板参数。不应遵循功能模板的模板参数包 通过另一个模板参数,除非该模板参数可以从参数类型列表中推导出来 或具有默认参数(14.8.2)

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


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

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

是允许的,因为可以推导出整数值。当然,这必须针对每种容器类型进行专门化,这与您想象的相去甚远。

如果我们有这样的东西,那就太棒了,因为它可以让我们轻松地写下一个特性。

在那之前,我们一直是专门化的。

如果你不知道一个非类型的模板参数的类型,那么你甚至无法匹配它。我担心你要求的东西太多了。@n.m.或者换句话说,值参数是二级模板参数。(使用包装器(
std::integral\u constant
)来避免缺点。(他们应该在那里实现自动包装…)@n、 m:同意,对于“正常”参数来说已经不可能了。另一方面,添加可变参数是为了能够指定更通用的模板,所以有希望添加/将添加类似的内容。可能您对这些问题的答案感兴趣。我认为您将用此解决的问题通常可以解决通过使用duck类型(例如,“如果它的行为像一个容器”+
auto
/
decltype(*begin(param))
,而不是直接检查参数的参数)或子类化(创建一个新的派生类来更改模板参数)进行编辑.Hmm.我也刚读了这一节,根据那一节int…或类似的内容,甚至是根本不允许的,我很确定,但是clang至少支持这一点。感谢你指出这一点。我进一步研究了这一点,我认为答案现在就在那里。是的,这将适用于STl容器的特定情况。但是Qt容器例如,我没有分配器,我也在寻找更通用的东西,容器只是一个例子。
template<class Container> class get_value_type {
public:
  typedef typename Container::value_type type; // common implementation
};
template<class X> class get_value_type< YourTrickyContainer<X> > {
  ......
public:
  typedef YZ type;
};
template<class ... Types> struct Tuple { };
template<T ...Values> struct Tuple2 { };
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
template<class ... Types, size_t ...Sizes> struct Tuple { };
template < typename... Args, size_t... N > void g(const std::array< Args, N > &...arr);
g(std::array< double, 3 >(), std::array< int, 5>());