在编译时使用 C++ 从另一个数组中提取数组
extract an array from another array at compile time using c++
不确定是否有可能用于更高版本的 c++。(我无法弄清楚使用传统的 c++ 来实现以下行为。
例如
如果我有一个像这样定义的数组:
在头文件中
struct Def {
static const int N = 5;
static const double data[N];
};
在其CPP中
const double Def::data[Def::N] = {0,1,2,3,4};
是否可以有一个模板get_subarray
这样
get_subarray<Def,2,0>::data
将是一系列内容{0,2,4}
get_subarray<Def,2,1>::data
将是一系列内容{1,3}
哪里
template<typename T, int M, int m>
struct get_phase {
// some code for the array variable data which will
// extract element from T::data for every M sample offset by index m
};
如评论中所述,OP 也对基于 C++14 的解决方案感兴趣。
这是其中之一:
#include<functional>
#include<cstddef>
#include<utility>
#include<array>
template<std::size_t O, typename T, std::size_t N, std::size_t... I>
constexpr std::array<T, sizeof...(I)>
f(const std::array<T, N> &arr, std::index_sequence<I...>) {
return { std::get<I+O>(arr)... };
}
template<std::size_t B, std::size_t E, typename T, std::size_t N>
constexpr auto f(const std::array<T, N> &arr) {
return f<B>(arr, std::make_index_sequence<E-B>());
}
int main() {
constexpr std::array<int, 3> a1 = { 0, 1, 2 };
constexpr auto a2 = f<1, 2>(a1);
static_assert(a1[1] == a2[0], "!");
}
在这种情况下,a2
等于 { 1 }
。
值得检查B
和E
以验证E
大于B
,但该示例应该给出执行此操作的方法。
要将其移植到 C++11,请执行以下操作:
不要使用
auto
作为返回类型,而是显式指定std::array
(简单(在 Web 上搜索可用的 C++11
integer_sequence
和make_index_sequence
实现之一并使用它
如果明确索引而不使用范围是可以的,这里有一个应该在 C++11 中工作的朴素片段:
#include<cstddef>
#include<utility>
#include<array>
template<std::size_t... I, typename T, std::size_t N>
constexpr std::array<T, sizeof...(I)>
f(const std::array<T, N> &arr) {
return { std::get<I>(arr)... };
}
int main() {
constexpr std::array<int, 3> a1 = { 0, 1, 2 };
constexpr auto a2 = f<1>(a1);
static_assert(a1[1] == a2[0], "!");
}
与前面的示例一样,a2
{ 1 }
。
skypjack的解决方案,但它不会提取请求的值。 Skypjack的版本有两个参数,"开始"和"结束"。 OP要求"步幅"或"频率"和"开始"。
我已经修改了它以匹配 OP 请求的"频率"和"开始"参数,为模板非类型参数提供更多自我解释的名称,并重写了几个索引计算:
#include<utility>
#include<iostream>
#include<array>
template <std::size_t Freq, std::size_t Start, typename T, std::size_t Dim,
std::size_t... I>
constexpr std::array<T, sizeof...(I)>
extractHelper (const std::array<T, Dim> & arr,
std::integer_sequence<std::size_t, I...>)
{ return { { std::get<Freq*I+Start>(arr)... } }; }
template <std::size_t Freq, std::size_t Start, typename T, std::size_t Dim>
constexpr auto extractSamples (const std::array<T, Dim> & arr)
{ return extractHelper<Freq, Start>
(arr, std::make_index_sequence<(Dim+Freq-1-Start)/Freq>()); }
下面是一些测试代码:
int main()
{
constexpr std::array<int, 8> a1 = { { 0, 1, 2, 3, 4, 5, 6, 7 } };
constexpr auto e1 = extractSamples<2, 0>(a1);
constexpr auto e2 = extractSamples<2, 1>(a1);
constexpr auto e3 = extractSamples<3, 0>(a1);
constexpr auto e4 = extractSamples<3, 1>(a1);
constexpr auto e5 = extractSamples<3, 2>(a1);
std::cout << "samples<2, 0>: ";
for ( auto const & i : e1 )
std::cout << ' ' << i;
std::cout << "nsamples<2, 1>: ";
for ( auto const & i : e2 )
std::cout << ' ' << i;
std::cout << "nsamples<3, 0>: ";
for ( auto const & i : e3 )
std::cout << ' ' << i;
std::cout << "nsamples<3, 1>: ";
for ( auto const & i : e4 )
std::cout << ' ' << i;
std::cout << "nsamples<3, 2>: ";
for ( auto const & i : e5 )
std::cout << ' ' << i;
std::cout << std::endl;
return 0;
}
输出为:
samples<2, 0>: 0 2 4 6
samples<2, 1>: 1 3 5 7
samples<3, 0>: 0 3 6
samples<3, 1>: 1 4 7
samples<3, 2>: 2 5
与OP的要求相匹配
这是 C++11 中不含添加剂的解决方案。照常编译时递归弥补了 C++14 std::index_sequence
的缺失- 在这种情况下,通过递归组合索引列表选择所需的数据数组样本。
给定一些:
constexpr std::array<T,N> data{{...}};
使用您选择的T
初始化...
,然后:
constexpr auto sample = get_sample<Stride,Offset>(data);
将sample
定义为编译时
std::array<T,M>
填充通过选择元素获得的data
的M
元素从连续Stride
大小间隔开始的偏移Offset
data
.
#include <array>
#include <type_traits>
constexpr std::size_t
sample_size(std::size_t size, std::size_t stride, std::size_t off)
{
return stride == 0 ? 0 : ((size - off) / stride) +
(off + (((size - off) / stride) * stride) < size);
}
template<
std::size_t Stride = 1, std::size_t Off = 0,
typename T, std::size_t Size, std::size_t ...Is
>
constexpr typename std::enable_if<
sizeof ...(Is) == sample_size(Size,Stride,Off),
std::array<T, sample_size(Size,Stride,Off)>
>::type
get_sample(std::array<T,Size> const & data)
{
return std::array<T,sample_size(Size,Stride,Off)>{{data[Is]... }};
}
template<
std::size_t Stride = 1, std::size_t Off = 0,
typename T, std::size_t Size, std::size_t ...Is
>
constexpr typename std::enable_if<
sizeof ...(Is) != sample_size(Size,Stride,Off),
std::array<T, sample_size(Size,Stride,Off)>
>::type
get_sample(std::array<T,Size> const & data)
{
return
get_sample<Stride,Off,T,Size,Is...,(sizeof...(Is) * Stride) + Off>
(data);
}
默认情况下,Stride
1
,Off
0
。帮助程序函数sample_size
嵌入约定,如果Stride
为 0,则得到一个空样本。
对于说明性程序,您可以附加:
constexpr std::array<int,5> data1{{0,1,2,3,4}};
constexpr auto sample1 = get_sample(data1);
constexpr auto sample2 = get_sample<2>(data1);
constexpr auto sample3 = get_sample<2,1>(data1);
constexpr auto sample4 = get_sample<6>(data1);
constexpr auto sample5 = get_sample<6,5>(data1);
static_assert(sample5.size() == 0,"");
constexpr std::array<float,6> data2{{1.1,2.2,3.3,4.4,5.5,6.6}};
constexpr auto sample6 = get_sample<2>(data2);
constexpr auto sample7 = get_sample<2,3>(data2);
constexpr auto sample8 = get_sample<3,2>(data2);
constexpr std::array<int,0> data3{};
constexpr auto sample9 = get_sample<0>(data3);
static_assert(sample9.size() == 0,"");
constexpr auto sample10 = get_sample<2>(data3);
static_assert(sample10.size() == 0,"");
#include <iostream>
int main()
{
std::cout << "get_sample<> of {0,1,2,3,4}n";
for (auto const & e : sample1) {
std::cout << e << ' ';
}
std::cout << 'n';
std::cout << "get_sample<2> of {0,1,2,3,4}n";
for (auto const & e : sample2) {
std::cout << e << ' ';
}
std::cout << 'n';
std::cout << "get_sample<2,1> of {0,1,2,3,4}n";
for (auto const & e : sample3) {
std::cout << e << ' ';
}
std::cout << 'n';
std::cout << "get_sample<6> of {0,1,2,3,4}n";
for (auto const & e : sample4) {
std::cout << e << ' ';
}
std::cout << 'n';
std::cout << "get_sample<2> of {{1.1,2.2,3.3,4.4,5.5,6.6}}n";
for (auto const & e : sample6) {
std::cout << e << ' ';
}
std::cout << 'n';
std::cout << "get_sample<2,3> of {{1.1,2.2,3.3,4.4,5.5,6.6}}n";
for (auto const & e : sample7) {
std::cout << e << ' ';
}
std::cout << 'n';
std::cout << "get_sample<3,2> of {{1.1,2.2,3.3,4.4,5.5,6.6}}n";
for (auto const & e : sample8) {
std::cout << e << ' ';
}
std::cout << 'n';
return 0;
}
其中报告:
get_sample<> of {0,1,2,3,4}
0 1 2 3 4
get_sample<2> of {0,1,2,3,4}
0 2 4
get_sample<2,1> of {0,1,2,3,4}
1 3
get_sample<6> of {0,1,2,3,4}
0
get_sample<2> of {1.1,2.2,3.3,4.4,5.5,6.6}
1.1 3.3 5.5
get_sample<2,3> of {1.1,2.2,3.3,4.4,5.5,6.6}
4.4 6.6
get_sample<3,2> of {1.1,2.2,3.3,4.4,5.5,6.6}
3.3 6.6
现场观看
如果你想把它应用到你的类Def
,你会在方式像:
struct Def {
static constexpr int N = 5;
static constexpr std::array<double,N> data{{0,1,2,3,4}};
};
并获取编译时示例,如下所示:
constexpr auto s = get_sample<2,1>(Def::data);
(g++ 6.1/clang++ 3.8, -std=c++11 -wall -wextra -pedantic(
- 在c++中为double类型的数组创建一个unique_ptr
- 从数组构造一个跨度<shared_ptr<T>><shared_ptr<void>>
- 给定一个单词数组和一个字符串,如何计算给定字符串中的所有单词
- 如何将 v8::FunctionCallbackInfo<v8::Value> 数组从一个隔离复制到另一个隔离?
- 我怎么能有一个以2D数组为参数的函数,而数组有一个我想更改的参数/维度
- 为什么我的数组输出一个不在其中的元素
- 数组 - 最后一个索引
- 将数组作为一个参数从一个函数传递到C 中的另一个函数
- 从字符串数组创建一个字符数组
- 如何在C 中的小写中将文本从数组的一个维度传递到另一个维度
- 在对结构数组的一个成员进行排序后,移动其成员的其余部分
- 为什么数组在一个文件中打印,但在发送到另一个文件时却缺少数字
- C++,为什么多维数组的一个元素的增加似乎增加了另一个元素
- 将数组的一个元素与整个数组元素进行比较
- 如何将数组从一个函数传递到另一个函数
- 查找最大和连续子数组-另一个版本
- 使用for循环将char数组的一个元素复制到另一个元素
- C++如何将变量char数组从一个函数传递到另一个函数
- 数组 ->另一个空的 int 数组混淆
- 用另一个字符数组替换一个字符数组