假设我的类型A
没有默认构造函数:
struct A
{
int x;
A(int x) : x(x) {}
};
我想制作一个std::array
A
。我可以使用初始化列表轻松地创建它:
std::array<A, 5> arr = { 0, 1, 4, 9, 16 };
你可以在这里看到一个模式。是的,我可以使用生成器函数来计算数组的每个值:
int makeElement(size_t i)
{
return i * i;
}
std::array<A, 5> arr = {
makeElement(0),
makeElement(1),
makeElement(2),
makeElement(3),
makeElement(4)
};
是的,实际上我有超过5个元素(64,即)。所以不重复makeElement
64次会很好。我想出的唯一解决方案是使用可变参数模板将参数包解压缩到初始化列表中:https://ideone.com/yEWZVq(它还检查所有副本是否被正确删除)。此解决方案的灵感来自this question。
它有效,但我不想滥用可变参数模板来完成这么简单的任务。你知道,膨胀的可执行文件大小,减慢编译速度,所有这些。我想做这样的事情:
new
std::array
并将其返回我可以做一些肮脏的黑客在动态内存中实现它:https://ideone.com/tbw5lm但这并不比std::vector
更好,我根本没有这样的问题。
我不知道如何在自动记忆中做到这一点。即具有相同的方便功能返回std::array
值与所有这些东西后面的引擎盖。有什么想法吗?
我想,boost::container::static_vector
对我来说可能是个好方法。不幸的是,我无法将boost
用于该特定任务。
PS。请注意,这个问题更像是研究兴趣。在现实世界中,可变参数模板和std::vector
都可以正常工作。我只是想知道也许我错过了什么。
答案 0 :(得分:3)
我认为,你对代码臃肿的担忧被误解了。这是一个示例:
loadData: function (item) {
return $.ajax({
type: "POST",
url: "url.html?cmd=fill",
data: null,
dataType: "json",
success: function (data) {
var list=eval(data);
//this loop is for example
for(var i=0;i<list.length;i++)
{
list[i].id=i+1;
//how to bind this list to Grid Fields
}
}
});
}
它产生非常整洁的装配:
#include <utility>
#include <array>
template<std::size_t... ix>
constexpr auto generate(std::index_sequence<ix...> ) {
return std::array<int, sizeof...(ix)>{(ix * ix)...};
}
std::array<int, 3> check() {
return generate(std::make_index_sequence<3>());
}
std::array<int, 5> glob = generate(std::make_index_sequence<5>());
如你所见,看不到任何代码膨胀。静态数组是静态初始化的,对于自动数组,它只是一堆移动。如果你认为一堆动作是一个可怕的代码臃肿,请考虑循环展开 - 每个人都喜欢!
顺便说一下,没有其他符合要求的解决方案。在构造时使用聚合初始化初始化数组,因此元素应该是默认可构造的或者是初始化的。
答案 1 :(得分:2)
这是另一种允许发生器输入任意范围的方法:
以下是用例:
/// generate an integer by multiplying the input by 2
/// this could just as easily be a lambda or function object
constexpr int my_generator(int x) {
return 2 * x;
}
int main()
{
// generate a std::array<int, 64> containing the values
// 0 - 126 inclusive (the 64 acts like an end() iterator)
static constexpr auto arr = generate_array(range<int, 0, 64>(),
my_generator);
std::copy(arr.begin(), arr.end(), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
}
这是允许其工作的样板
#include <utility>
#include <array>
#include <iostream>
#include <algorithm>
#include <iterator>
/// the concept of a class that holds a range of something
/// @requires T + 1 results in the next T
/// @requires Begin + 1 + 1 + 1.... eventually results in Tn == End
template<class T, T Begin, T End>
struct range
{
constexpr T begin() const { return Begin; }
constexpr T end() const { return End; }
constexpr T size() const { return end() - begin(); }
using type = T;
};
/// offset every integer in an integer sequence by a value
/// e.g offset(2, <1, 2, 3>) -> <3, 4, 5>
template<int Offset, int...Is>
constexpr auto offset(std::integer_sequence<int, Is...>)
{
return std::integer_sequence<int, (Is + Offset)...>();
}
/// generate a std::array by calling Gen(I) for every I in Is
template<class T, class I, I...Is, class Gen>
constexpr auto generate_array(std::integer_sequence<I, Is...>, Gen gen)
{
return std::array<T, sizeof...(Is)> {
gen(Is)...
};
}
/// generate a std::array by calling Gen (x) for every x in Range
template<class Range, class Gen>
constexpr auto generate_array(Range range, Gen&& gen)
{
using T = decltype(gen(range.begin()));
auto from_zero = std::make_integer_sequence<typename Range::type, range.size()>();
auto indexes = offset<range.begin()>(from_zero);
return generate_array<T>(indexes, std::forward<Gen>(gen));
}
/// generate an integer by multiplying the input by 2
constexpr int my_generator(int x) {
return 2 * x;
}
int main()
{
static constexpr auto arr = generate_array(range<int, 0, 64>(),
my_generator);
std::copy(arr.begin(), arr.end(), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
}
这里是在汇编之前查看的代码膨胀:
.LC0:
.string ", "
main:
;; this is the start of the code that deals with the array
pushq %rbx
movl main::arr, %ebx
.L2:
movl (%rbx), %esi
movl std::cout, %edi
addq $4, %rbx
;; this is the end of it
;; all the rest of this stuff is to do with streaming values to cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
movl $2, %edx
movl $.LC0, %esi
movl std::cout, %edi
call std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
cmpq main::arr+256, %rbx
jne .L2
movl std::cout, %edi
call std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)
xorl %eax, %eax
popq %rbx
ret
subq $8, %rsp
movl std::__ioinit, %edi
call std::ios_base::Init::Init()
movl $__dso_handle, %edx
movl std::__ioinit, %esi
movl std::ios_base::Init::~Init(), %edi
addq $8, %rsp
jmp __cxa_atexit
main::arr:
.long 0
.long 2
.long 4
.long 6
.long 8
.long 10
.long 12
.long 14
.long 16
.long 18
.long 20
.long 22
.long 24
.long 26
.long 28
.long 30
.long 32
.long 34
.long 36
.long 38
.long 40
.long 42
.long 44
.long 46
.long 48
.long 50
.long 52
.long 54
.long 56
.long 58
.long 60
.long 62
.long 64
.long 66
.long 68
.long 70
.long 72
.long 74
.long 76
.long 78
.long 80
.long 82
.long 84
.long 86
.long 88
.long 90
.long 92
.long 94
.long 96
.long 98
.long 100
.long 102
.long 104
.long 106
.long 108
.long 110
.long 112
.long 114
.long 116
.long 118
.long 120
.long 122
.long 124
.long 126
即。没什么。