我希望有一种机制允许我将可变参数函数参数(所有这些参数都可转换为某些特定的普通旧数据类型F
的值)连接到适当大小的原始数据存储中(大小为大于或等于参数大小的总和)。我写了以下代码:
#include <iostream>
#include <iterator>
#include <new>
#include <cstdlib>
#include <cassert>
#include <array>
#include <tuple>
template< typename F >
struct repacker
{
constexpr
repacker(F * const _storage)
: storage_(_storage)
{
static_assert(std::is_pod< F >::value, "Underlying type is not a POD type.");
}
F * const storage_;
template< typename... P >
auto operator () (P && ...params) const
{
constexpr auto N = sizeof...(P);
using A = std::array< F, N >; // using A = F [N]; this eliminates the problem
static_assert(sizeof(A) == sizeof(F) * N, "This compiler does not guarantee, that this code to be working.");
#ifndef _NDEBUG
auto a =
#else
std::ignore =
#endif
new (storage_) A{F(params)...};
assert(static_cast< void * >(a) == static_cast< void * >(a->data()));
return N;
}
};
int main()
{
using F = double;
constexpr auto N = 6;
F * a = new F[N];
{
F x(1.0);
F const y(2.0);
repacker< F > r(a);
auto const M = r(x, y, 3.0, 4, 5.0f, 6.0L);
assert(M == N);
}
std::copy(a, a + N, std::ostream_iterator< F const & >(std::cout, " "));
std::cout << std::endl;
delete [] a;
return EXIT_SUCCESS;
}
但我不确定所有编译器的assert(static_cast< void * >(&a) == static_cast< void * >(a.data()));
断言都是正确的。这是代码工作的必要条件。
总是断言是真的吗?
答案 0 :(得分:5)
这是代码工作的必要条件。
不,不是。好的,这是必要的,但它不是足够的。这个(非常可怕的)代码的另一个必要条件是:
sizeof(std::array<F, N>) == sizeof(F) * N;
这是不标准保证。 std::array
与C样式数组不是布局兼容的。 std::array
的内容是,但不是完整类型本身。
如果要初始化内存中的某个对象(以位块为单位),则应该新建char[]
数组,而不是F
数组。你应该分配这个:
char *a = new char[sizeof(std::array<F, N>)];
答案 1 :(得分:3)
答案 2 :(得分:1)
标准布局类型保证您可以使用reinterpret_cast
将指向它们的指针转换为其第一个成员的指针。 IIRC reinterpret_cast
可能会返回与用作输入的地址不同的地址(由于对齐限制)。