C++ 14:如何使用可变参数模板创建值 1-100 的数组
C++ 14: How to use variadic template to create an array of values 1-100
我希望获得一组值 int buf[]={1...100}
。我希望这个数组可以在编译时使用可变参数模板构建。这就像 Python/Haskell 等的列表理解
但是 c++11/14 模板可以做到吗?如何做到的?
谢谢
好吧,这不是编译时间,但通常情况下,我希望大多数代码使用 std::iota
。在某些情况下,这实际上可能比编译时魔术更快,因为编译时数组需要存储在可执行文件的 .data
段中;如果数组足够大,从 .data
中读取额外的磁盘页面最终可能比写入从 OS.
中新鲜提取的纯内存页面慢
简单的用法是:
int buf[100];
std::iota(&buf[0], &buf[100], 1);
坦率地说,我会从这里开始,只有在运行时初始化方面存在已证实的性能问题时,我才会开始研究模板魔术。
这应该适用于 c++14。它通过递归模板实例化将所有值初始化为 constexpr
。您应该能够通过更改模板参数将顺序值的大小更改为您需要的任何大小。请注意,对于非常大的数组,它可能会达到递归限制:
#include <array>
template<int NumVal, int ArrSize>
constexpr void setVal(std::array<int, ArrSize> &constArr) {
std::get<NumVal>(constArr) = NumVal + 1;
if(NumVal) setVal<NumVal ? NumVal - 1 : 0, ArrSize>(constArr);
}
template<int ArrSize>
constexpr auto arrRange() -> std::array<int, ArrSize> {
std::array<int, ArrSize> tmp{};
setVal<ArrSize - 1, ArrSize>(tmp);
return tmp;
}
constexpr std::array<int, 100> constArr = arrRange<100>();
int main() {
for(int itr = 0; itr < 100; ++itr) printf("%d ", constArr[itr]);
}
如果你真的打算在编译时做这个。您可以使用 integer_sequence
和 std::array
#include <utility>
#include <array>
template <int... Is> // when called below, Is will be 0 - N
constexpr std::array<int, sizeof...(Is)> make_inc_array_impl(
std::integer_sequence<int, Is...>) {
return {{(Is + 1)...}}; // +1 to start at one instead of [0, 1, ...]
}
template <std::size_t N>
constexpr std::array<int, N> make_inc_array() {
return make_inc_array_impl(std::make_integer_sequence<int, N>{});
}
然后用你的尺码来电
constexpr auto a = make_inc_array<100>(); // [1, 2, ..., 100]
这远不如列表理解灵活,您可能最好只使用 std::iota
并在运行时初始化。
C++14 允许在编译时循环。
constexpr auto make_upto_100() {
std::array< int, 100 > ret = {};
for ( int i = 0; i != 100; ++ i ) ret[i] = i + 1;
return ret;
}
C++11 允许像 make_index_sequence
这样的实用程序,它可能更像您的想法。 (C++14 也有 std::[make_]index_sequence
。)
template< std::size_t ... i >
struct index_sequence
{ typedef index_sequence< i ..., sizeof ... (i) > next; };
template< std::size_t last >
struct index_seq_maker
{ typedef typename index_seq_maker< last - 1 >::type::next type; };
template<>
struct index_seq_maker< 0 >
{ typedef index_sequence<> type; };
template< std::size_t n >
using make_index_sequence = typename index_seq_maker< n >::type;
template< int ... i >
constexpr
std::array< int, 100 >
make_upto_100( index_sequence< i ... > )
{ return {{ i + 1 ... }}; }
constexpr
std::array< int, 100 > upto_100() = make_upto_100( make_index_sequence< 100 >{} );
我希望获得一组值 int buf[]={1...100}
。我希望这个数组可以在编译时使用可变参数模板构建。这就像 Python/Haskell 等的列表理解
但是 c++11/14 模板可以做到吗?如何做到的? 谢谢
好吧,这不是编译时间,但通常情况下,我希望大多数代码使用 std::iota
。在某些情况下,这实际上可能比编译时魔术更快,因为编译时数组需要存储在可执行文件的 .data
段中;如果数组足够大,从 .data
中读取额外的磁盘页面最终可能比写入从 OS.
简单的用法是:
int buf[100];
std::iota(&buf[0], &buf[100], 1);
坦率地说,我会从这里开始,只有在运行时初始化方面存在已证实的性能问题时,我才会开始研究模板魔术。
这应该适用于 c++14。它通过递归模板实例化将所有值初始化为 constexpr
。您应该能够通过更改模板参数将顺序值的大小更改为您需要的任何大小。请注意,对于非常大的数组,它可能会达到递归限制:
#include <array>
template<int NumVal, int ArrSize>
constexpr void setVal(std::array<int, ArrSize> &constArr) {
std::get<NumVal>(constArr) = NumVal + 1;
if(NumVal) setVal<NumVal ? NumVal - 1 : 0, ArrSize>(constArr);
}
template<int ArrSize>
constexpr auto arrRange() -> std::array<int, ArrSize> {
std::array<int, ArrSize> tmp{};
setVal<ArrSize - 1, ArrSize>(tmp);
return tmp;
}
constexpr std::array<int, 100> constArr = arrRange<100>();
int main() {
for(int itr = 0; itr < 100; ++itr) printf("%d ", constArr[itr]);
}
如果你真的打算在编译时做这个。您可以使用 integer_sequence
和 std::array
#include <utility>
#include <array>
template <int... Is> // when called below, Is will be 0 - N
constexpr std::array<int, sizeof...(Is)> make_inc_array_impl(
std::integer_sequence<int, Is...>) {
return {{(Is + 1)...}}; // +1 to start at one instead of [0, 1, ...]
}
template <std::size_t N>
constexpr std::array<int, N> make_inc_array() {
return make_inc_array_impl(std::make_integer_sequence<int, N>{});
}
然后用你的尺码来电
constexpr auto a = make_inc_array<100>(); // [1, 2, ..., 100]
这远不如列表理解灵活,您可能最好只使用 std::iota
并在运行时初始化。
C++14 允许在编译时循环。
constexpr auto make_upto_100() {
std::array< int, 100 > ret = {};
for ( int i = 0; i != 100; ++ i ) ret[i] = i + 1;
return ret;
}
C++11 允许像 make_index_sequence
这样的实用程序,它可能更像您的想法。 (C++14 也有 std::[make_]index_sequence
。)
template< std::size_t ... i >
struct index_sequence
{ typedef index_sequence< i ..., sizeof ... (i) > next; };
template< std::size_t last >
struct index_seq_maker
{ typedef typename index_seq_maker< last - 1 >::type::next type; };
template<>
struct index_seq_maker< 0 >
{ typedef index_sequence<> type; };
template< std::size_t n >
using make_index_sequence = typename index_seq_maker< n >::type;
template< int ... i >
constexpr
std::array< int, 100 >
make_upto_100( index_sequence< i ... > )
{ return {{ i + 1 ... }}; }
constexpr
std::array< int, 100 > upto_100() = make_upto_100( make_index_sequence< 100 >{} );