C++0x 元组向后存储元素
经过一番调查,我发现 C++0x 在内存中向后存储元组中的元素。
例如,采用以下代码:
std::tuple<char, char, char> x('\0', 'b', 'a');
char* y = (char*)&x;
std::cout << sizeof(x) << std::endl;
std::cout << y << std::endl;
当使用 GCC 4.5.2 编译时,我得到以下输出:
3
ab
这最初让我感到困惑。为什么数据会倒着存储?在搜索 GNU 无意中混淆的标头后,我注意到实现与此类似:
template<typename head, typename... tail> class tuple<head, tail...> : public tuple<tail...>
{
head value;
...
};
因为基类包含最后一个元素,然后下一个派生类包含倒数第二个元素,依此类推,模板参数的实际顺序是相反的。
当我第一次接触元组时,我认为我可以将它们用于像 glInterleavedArrays()
这样的函数,它将顶点数据数组设置为颜色、纹理坐标、法线和点的元组。当然,如果我创建一个元组数组,则必须反向输入这些数据,如果您碰巧忘记按正确的顺序放置参数,这可能会导致非常奇怪的错误。
那么像这样的事情呢?
template<typename... head, typename tail> class tuple<head..., tail> : public tuple<head...>
{
tail value;
...
};
在 GCC 4.5.2 下:
错误:参数包参数“head ...”必须位于模板参数列表的末尾
除非将来可用,否则我几乎一直在寻找另一种方法来实现它。还有别的办法吗?有什么方法可以欺骗 GCC 在内存方面获得正确排序的元组吗?
After a bit of investigation, I found that C++0x stores the elements in a tuple backwards in memory.
For example, take this code:
std::tuple<char, char, char> x('\0', 'b', 'a');
char* y = (char*)&x;
std::cout << sizeof(x) << std::endl;
std::cout << y << std::endl;
When compiled with the GCC 4.5.2, I get the following output:
3
ab
This initially puzzled me. Why is the data stored backwards? After hunting through GNU's unintentionally obfuscated headers, I noticed that the implementation was similar to this:
template<typename head, typename... tail> class tuple<head, tail...> : public tuple<tail...>
{
head value;
...
};
Because the base class contains the last element, then the next derived class contains the second to last, etc., the actual order of the template arguments is reversed.
When I first got into tuples, I thought that I could use them for a function like glInterleavedArrays()
, which sets an array of vertex data as tuples of colors, texture coordinates, normals, and points. Of course, if I make an array of tuples, this data will have to be inputted in reverse, which can result in really weird bugs if you happen to forget to put the arguments in the right order.
What about something like this, then?
template<typename... head, typename tail> class tuple<head..., tail> : public tuple<head...>
{
tail value;
...
};
Under the GCC 4.5.2:
error: parameter pack argument ‘head ...’ must be at the end of the template argument list
Unless this becomes available in the future, I'm pretty much stuck on finding another way to implement this. Is there another way? Some way to trick the GCC into getting a properly-ordered tuple memory-wise?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您正在探索的元组布局是元组的未指定实现细节。其他实现将有其他布局。如果您写入此代码,根据 gcc 的布局,您的代码可能无法移植到其他 std::libs。
例如,libc++ 元组实现具有相反的(按顺序)布局。
The tuple layout that you are exploring is an unspecified implementation detail of tuple. Other implementations will have other layouts. If you write to this one, depending on gcc's layout, your code may not be portable to other std::libs.
The libc++ tuple implementation (for example) has the opposite (in-order) layout.
为什么你关心元组的实现是什么? 对接口编程,而不是实现。
如果您仅通过其广告接口使用元组,那么您将按照放入对象的顺序取出对象。如果您通过直接访问其内容来打破封装,例如通过示例中的狡猾的指针强制转换,那么所有赌注已经落空了。
Why do you care what the implementation of tuple is? Program to an interface, not an implementation.
If you only use tuple via its advertised interface, then you will get your objects out in the same order you put them in. If you instead break encapsulation by accessing its contents directly, for example by the dodgy pointer cast in your example, then all bets are off.