c++ - 将非类型参数包分布在不同的模板参数包中

标签 c++ templates c++17 variadic-templates index-sequence

是否有任何语法可以让我在模板参数包的参数之间分发非类型参数包,并期望非类型包(不同大小)?由于这非常令人困惑,我相信一个例子可能有助于澄清我的意思: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 的行使用与我类似的语法。显然,如果我编写一个特殊的构造函数来处理这种情况,它会工作得很好。不过,我希望它适用于任意数量的容器,而无需我针对所有可能的情况明确说明它。例如,如果我有 2 个容器 a,b,其索引集 {0,1,2}{0,1,2,3} 扩展应类似于 A(a[0],a[1],a[2], b[0],b[1],b[2],b[3]).

我知道我可以递归地执行此操作,一次解压一个容器,然后递归地委托(delegate)给构造函数,期望一开始只包含一系列平面元素。我的问题是这是否可以以更优雅、更高效、更简洁的方式实现。

最佳答案

For example, if I have 2 containers a,b, with index sets {0,1,2} and {0,1,2,3} the expansion should look like A(a[0],a[1],a[2], b[0],b[1],b[2],b[3]).

I am aware that I could do this recursively, unpacking one container at a time, and delegating recursively to constructors expecting a sequence of only flat elements in the beginning. My question is whether this is feasible in a more elegant, efficient, and less verbose way.

您是否接受这样的解决方案:扩展为您提供带有 a[0],a[1],a[2], b[0],b 的 std::tuple [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]...); } 

您可以开始编写构造函数,调用委托(delegate)构造函数,如下所示

   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
 }

关于c++ - 将非类型参数包分布在不同的模板参数包中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58543122/

相关文章:

c++ - 使用模板时的类型推断

java - 如何对按钮单击使用react以更改 map 中的参数?

c++ - 是否需要对具有格式错误的默认模板参数的未使用成员模板进行诊断?

c++ - WWSAPI 双工 channel 服务

c++ - 自动返回类型推导是否强制多个函数具有相同的返回类型?

c++ - std::vector<std::wstring> 移动/重新分配内部 wstring.data() 合法吗?

c++ - 如何在 C++ 中使用 lambda 作为具有默认值的模板参数?

c++ - STL 表示隐含交叉引用的数据结构的方法

C++ 破坏基类导致调试断言失败

c++ - 这个数组大小模板是如何工作的?