在不同的模板参数包之间分发非类型参数包
Distribute non-type parameter pack across different template parameter packs
有没有任何语法可以让我在模板参数包的参数之间分发非类型参数包,期望非类型包(不同大小(?由于这很令人困惑,我相信一个例子可能有助于澄清我的意思:https://godbolt.org/z/FaEGTV
template <typename T, int... I> struct Vec { };
struct A
{
template<template<typename, int...> typename... Container,
typename... Ts, int... Is>
A(Container<Ts,Is...>... );
};
A a(Vec<int, 0>{}, Vec<double, 0>{}); // ok
A b(Vec<int, 0, 1>{}, Vec<double, 0, 1>{}); // ok
A c(Vec<int, 0>{}, Vec<double, 0, 1>{}); // error
我希望标记为// error
的行使用与我所使用的语法类似的语法。显然,如果我编写一个特殊的构造函数来处理这种情况,它会很好地工作。然而,我希望这适用于任何数量的容器,而不必为所有可能的情况明确说明。例如,如果我有两个容器a,b
,其中包含索引集{0,1,2}
和{0,1,2,3}
,那么扩展应该看起来像A(a[0],a[1],a[2], b[0],b[1],b[2],b[3])
。
我知道我可以递归地完成这项工作,一次拆包一个容器,并递归地委托给一开始只期望一个平面元素序列的构造函数。我的问题是,以一种更优雅、高效、不那么冗长的方式,这是否可行。
例如,如果我有两个容器
a,b
,其中包含索引集{0,1,2}
和{0,1,2,3}
,那么扩展应该看起来像A(a[0],a[1],a[2], b[0],b[1],b[2],b[3])
。我知道我可以递归地完成这项工作,一次拆包一个容器,并递归地委托给一开始只期望一个平面元素序列的构造函数。我的问题是,以一种更优雅、高效、不那么冗长的方式,这是否可行。
您是否接受扩展为std::tuple
和a[0],a[1],a[2], b[0],b[1],b[2],b[3]
的解决方案?
在这种情况下,您可以遵循Igor的建议,解压缩容器中的值,并将它们重新打包为元组,然后使用std::tuple_cat()
来连接元组。
我的意思是。。。给定如下的容器/元组转换器
template <template<typename, std::size_t...> typename C,
typename T, std::size_t... Is>
auto getTpl (C<T, Is...> const & v)
{ return std::make_tuple(v.data[Is]...); }
您可以开始编写构造函数,调用委托构造函数,如下所示
template <typename ... Ts>
A (Ts const & ... ts) : A{ std::tuple_cat( getTpl(ts)... ) }
{ }
最后的构造函数是
template <typename ... Ts>
A (std::tuple<Ts...> const & tpl)
{ /* do something with values inside tpl */ }
以下是的完整编译示例
#include <iostream>
#include <string>
#include <tuple>
template <typename T, std::size_t ... Is>
struct Vec
{
T data [sizeof...(Is)] = { Is... };
T const & operator[] (std::size_t i) const
{ return data[i]; }
T & operator[] (std::size_t i)
{ return data[i]; }
};
template <template<typename, std::size_t...> typename C,
typename T, std::size_t... Is>
auto getTpl (C<T, Is...> const & v)
{ return std::make_tuple(v.data[Is]...); }
struct A
{
template <typename ... Ts>
A (std::tuple<Ts...> const & tpl)
{ /* do something with values inside tpl */ }
template <typename ... Ts>
A (Ts const & ... ts) : A{ std::tuple_cat( getTpl(ts)... ) }
{ }
};
int main ()
{
A a(Vec<int, 0>{}, Vec<double, 0>{}); // ok
A b(Vec<int, 0, 1>{}, Vec<double, 0, 1>{}); // ok
A c(Vec<int, 0>{}, Vec<double, 0, 1>{}); // ok, now
}
我只想做:
template <typename T>
struct is_container_type : std::false_type{};
template<template<typename, size_t...> typename C, typename T, size_t... Is>
struct is_container_type<C<T, Is...>> : std::true_type
{
// Potential `using` to retrieve C, T, Is...
};
struct A
{
template<typename... Cs, REQUIRES(is_container_type<Cs>::value && ...)>
A(Cs... cs)
{
((void)(std::cout << cs << "n"), ...);
}
};
演示
使用multi_apply
(多元组的std::apply
版本((您可以在那里找到(,您可以执行:
struct A
{
template<typename... Ts, REQUIRES(!is_container_type<Ts>::value || ...)>
A(Ts... ts)
{
((std::cout << ts << " "), ...);
std::cout << std::endl;
}
template<typename... Cs, REQUIRES(is_container_type<Cs>::value && ...)>
A(Cs... cs) :
A(multiple_apply([](auto...args){ return A(args...); },
cs...) // if Cs is tuple-like
// as_tuple(cs)...) // convert Cs to tuple<int, /*..*/, int>
)
{
}
};
演示
我设法产生了一个效率有点低的解决方案,它在每个递归步骤的第一个参数中构建一个更大的向量,然后还有一个接受单个向量并将其扩展的构造函数。显然,这不是理想的,因为在最坏的情况下,N个矢量是用元素总数N^2/2
创建的。下面是一个示例实现,说明了我所做的操作:https://coliru.stacked-crooked.com/a/1f41f3793846cdb1
我尝试了一个不同的版本,其中没有构造新的对象,但由于某种原因(我认为这是由于多次扩展(,编译器未能推导出正确的构造函数——这个版本在上面链接的示例中的GROW_VECTOR 0
定义中。
- 在 c++ 中的模板实例化中使用带有构造函数的类作为类型参数
- 如何解决一元"*"(有"字符")错误的无效类型参数?
- "std::shared_ptr":不是参数"_Ty"的有效模板类型参数
- 具有可变参数非类型参数的模板专用化
- 函数类型参数的模板参数推导
- PowerShell 使用结构类型参数调用 C++ DLL 的导出函数
- 对于非常量指针类型的参数,未调用具有常量指针模板类型参数的功能
- 为模板传递非类型参数 agument
- 为什么带有类型参数的运算符 () 可以应用于 result_of 上下文中的类型?
- 使用其他模板类型参数作为要在函数签名中使用的类型别名声明
- 如何避免具有相同类型参数的函数中的错误
- 将内置类型变量传递给只有一个类类型参数的"+"运算符函数时自动类型转换的构造函数
- c++非类型参数包扩展
- 如何实现对参数顺序不可知的std::same_as的广义形式(即对于两个以上的类型参数)
- 在不同的模板参数包之间分发非类型参数包
- 如何在使用容器和字符串时强制使用显式分配器类型参数
- 错误:一元"*"的类型参数无效(具有"int"):使用 mergesort 计算
- EXPECT_CALL具有 unique_ptr 引用类型参数的模拟函数
- 作为模板类型参数,为什么 type[N] 与其专用版本不匹配----模板<类 T>类 S<T[]>
- C++ 模板:重载时找不到基类类型参数方法