【问题标题】:Convert a Tuple to a Struct in a Template将元组转换为模板中的结构
【发布时间】:2015-07-17 15:30:40
【问题描述】:

我正在学习 OpenGL 作为一项练习,并希望推出我自己的数学库,以便使用 C++11 模板轻松进行编程。此问题的解决方案不应调用运行时多态性。

基本的想法是我想要这样的东西(注意这显然不是有效的 C++ 代码):

template<class T, int n> //element type is T, size is n
class Vector {
    T v1, v2, ... , vn;
public:
    Vector(T v1, ... , T vn);
    ~Vector() noexcept;
    ...
    // more constructors and stuff here.
}

template<T, n>
Vector<T, n> operator +(Vector<T, n> lhs, Vector<T, n> rhs);

...
// more math functions and operators here...

问题是当这些向量作为数组传递给 OpenGL 函数时,我想将它们透明地转换为常规 C 结构。例如,对于n == 3,我想将我的Vector&lt;T, 3&gt; 转换为:

template<class T>
struct Vec3 {
    T v1, v2, v3;
}

这样我就可以打电话了:

Vector<float, 3> vertices[1];
vertices[0] = Vector<float, 3>(1.0f, 1.0f, 1.0f);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

让它正常工作,就好像我使用了 Vec3&lt;float&gt; 的数组一样。我希望 n == 2n == 3n == 4 有这种行为。我不想编写 3 个类并为每个类实现数学运算符。

我第一次尝试将 SFINAE 与强制转换运算符一起使用:operator T()

// Inside Vector's declaration...
public:
    operator typename std::enable_if<n == 3, Vec3<T>>::type();

这可能只适用于 n == 3,但我还需要:

    operator typename std::enable_if<n == 2, Vec2<T>>::type();
    operator typename std::enable_if<n == 4, Vec4<T>>::type();

当我实例化 Vector&lt;float, 3&gt; 时,g++ 抱怨 enable_if 没有用于 2 和 4 的 ::type 类型定义。

此时我使用std::array&lt;T, n&gt; 来保存我的值,但我意识到这并没有真正起作用。这是否意味着我的值实际上并不在类中,而是保存在其他地方,因此传递类的数组就像传递std::array&lt;T, n&gt; 的数组,而不是Vec3&lt;T&gt; 的数组?

我目前感兴趣的领域是使用std::tuple&lt;class... Types&gt;,因为它们将值直接存储在类中。这个想法有几个问题:

  1. 我想将元组的类型限制为只有一种类型,以便我的 Vector 是同质的。
  2. 我希望能够获得元组的大小而不将其存储在我的类中。
  3. 我仍然需要以某种方式实现operator Vec3&lt;T&gt;() 和朋友。
  4. 我不知道sizeof(tuple&lt;float, float, float&gt;) == sizeof(Vec3&lt;float&gt;) 是否有任何保证我可以安全地将tuple&lt;float, float, float&gt; 转换为Vec3&lt;float&gt; 的内存布局。例如,我听说 g++ 的 stdlib 在类中以相反的顺序存储元组值。

【问题讨论】:

  • 这听起来很有趣!虽然,我可能误读了您的实际问题 - 您似乎在问 std::array 的值存储在哪里。这是您正在寻找答案的问题吗?
  • 是的,事实证明这个问题的答案可以解决这个问题!请参阅下面我对 Angew 的评论。

标签: c++ templates c++11 reflection template-meta-programming


【解决方案1】:

std::array&lt;T, n&gt; 保证是对T[n] 的零开销包装器,因此您可以简单地将其存储在您的类中,并确保没有可能弄乱 OpenGL 调用的填充。

【讨论】:

  • 我现在意识到我的错误:我不记得动态数组和静态数组是不同的。静态数组存储在原地,因此 struct S1 {float v1, v2; };在内存中(模填充)与 struct S2 {float v[2];}; 相同。而仅存储指向浮点数的指针的结构在内存中与机器字相同。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-01
  • 1970-01-01
  • 2015-06-22
  • 1970-01-01
  • 2022-08-04
  • 1970-01-01
相关资源
最近更新 更多