如何打印通过引用传递的 glm::vec3 类型的向量值?

Posted

技术标签:

【中文标题】如何打印通过引用传递的 glm::vec3 类型的向量值?【英文标题】:How do I print vector values of type glm::vec3 that have been passed by reference? 【发布时间】:2012-07-17 03:04:30 【问题描述】:

我有一个小型 obj 加载器,它需要两个参数并将它们传递回输入变量。但是这是我第一次这样做,我现在不知道如何打印所述值。这是我测试加载程序是否正常工作的主要功能。我有两个glm::vec3 类型的向量来保存顶点和法线数据。

std::vector<glm::vec3> vertices;
std::vector<glm::vec3> normals;    

int main() 
    bool test = loadOBJ("cube.obj", vertices, normals);
    for (int i = 0; i < vertices.size(); i++) 
       std::cout << vertices[i] << std::endl;   // problem line
    

    return 0;   

上面评论的那一行是产生无用信息的原因。如果我这样离开它并运行程序,我会收到一堆错误(格式太长,无法粘贴到这里),如果我添加引用运算符,我会得到如下输出: p>

0x711ea0
0x711eac
0x711eb8
0x711ec4    // etc

知道我做错了什么吗?

【问题讨论】:

glm::vec3 是否超载operator&lt;&lt;?如果没有,您可能会更好地打印,例如,vertices[i].x &lt;&lt; ' ' &lt;&lt; vertices[i].y &lt;&lt; ' ' &lt;&lt; vertices[i].z 这是我在输出窗口中看到的许多乱码错误之一?不知道有没有。 向我们展示 glm:vec3 的定义。 @DeadMG,哎呀,我的意思是左值:p 当然你不要到处乱跑&amp;5&amp;"hi" 等等。 @iKlsR 关于打印花车的其他问题的答案是std::copy(std::begin(verts),std::end(verts),std::ostream_iterator&lt;float&gt;(std::cout, " ")); 【参考方案1】:

glm 对此有一个扩展。添加#include "glm/ext.hpp""glm/gtx/string_cast.hpp"

然后以打印向量为例:

glm::vec4 test;
std::cout<<glm::to_string(test)<<std::endl;

【讨论】:

NTS:您还需要添加GLM_ENABLE_EXPERIMENTAL,才能使用glm::to_string。 (glm 0.9.9.3) 给自己和其他 c/cpp n00bs 的注意事项:上面的注释意味着输入“#define GLM_ENABLE_EXPERIMENTAL 在包含之前也要输入!【参考方案2】:

我认为最优雅的解决方案可能是已经发布的两个答案的组合,并添加了模板,因此您不必为所有向量/矩阵类型重新实现运算符(这将函数定义限制为头文件,不过)。

#include <glm/gtx/string_cast.hpp>

template<typename genType>
std::ostream& operator<<(std::ostream& out, const genType& g)

    return out << glm::to_string(g);

【讨论】:

出于好奇:您的模板如何阻止此函数与 glm 以外的类型一起使用? 这只会给我“模棱两可的过载”。 @Ludwik 不幸的是,除了明智地放置模板和 operator&lt;&lt; 的现有模板专业化之外,别无其他,但我当时对 SFINAE 技术几乎没有经验(就此而言,仍然没有)所以我会把这个练习留给比我更有经验的人。不过,operator&lt;&lt; 通常专门用于内置类型,只要您不将它与类/结构/等一起使用。您还没有为您定义专业化,通常应该没问题。如果你得到“模棱两可的超载”,这意味着其他东西对&lt;&lt; 有一般的超载。 如果我没记错的话,我会得到 string 的“模棱两可的过载”。 SFINAE 仅在模板参数之一无法展开时才有效。要解决模棱两可的重载,请包含&lt;type_traits&gt;&lt;utility&gt;,然后使用template &lt;typename GLMType, typename = decltype(glm::to_string(std::declval&lt;GLMType&gt;()))&gt;【参考方案3】:

glm::vec3 不会重载operator&lt;&lt;,因此您无法打印矢量本身。但是,您可以做的是打印向量的成员:

std::cout << "" 
          << vertices[i].x << " " << vertices[i].y << " " << vertices[i].z 
          << "";

更好的是,如果你经常使用它,你可以自己重载operator&lt;&lt;

std::ostream &operator<< (std::ostream &out, const glm::vec3 &vec) 
    out << "" 
        << vec.x << " " << vec.y << " "<< vec.z 
        << "";

    return out;

然后打印,只需使用:

std::cout << vertices[i];

【讨论】:

嘿,如果我有一个大的、多文件的项目,我可以把这个重载放在哪里,以便它可以在任何地方使用? @Ludwik,请使用另一个答案中提到的扩展名(这个答案更普遍,但我缺乏对这个库的了解)。如果您需要这样的重载,它就像您重复使用的任何其他类或函数一样工作。将它的声明放入标题中,并在标题中将其定义为inline 以满足链接或在一个实现文件中定义。 我确实使用了接受答案的扩展名,但它需要在向量上调用glm::to_string,而我更喜欢&lt;&lt; 重载。谢谢,我会把它放在头文件中。 根据 glm 提供的内容可能会更好:operator &lt;&lt;(...) return out &lt;&lt; glm::to_string(vec); @LimitedAtonement,我同意。在编写第一个其他答案之前,我不知道此功能存在。至少答案在某些情况下可能仍然有用。【参考方案4】:

GLM 在&lt;glm/gtx/io.hpp&gt; 中有operator&lt;&lt;()

#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtx/io.hpp>

int main()

   glm::vec3 v(1.0f, 2.0f, 3.0f);
   std::cout << v << std::endl;

输出是:

[    1.000,    2.000,    3.000]

【讨论】:

【参考方案5】:

要正确解决重载问题,您可以执行以下操作:

// Writes a generic GLM vector type to a stream.
template <int D, typename T, glm::qualifier P>
std::ostream &operator<<(std::ostream &os, glm::vec<D, T, P> v) 
  return os << glm::to_string(v);


【讨论】:

【参考方案6】:

详细说明 JAB 的答案,我使用以下内容来避免 'operator &lt;&lt;' is ambiguous 错误:

#include <glm/glm.hpp>
#include <glm/gtx/string_cast.hpp>

/**
 * can_cout<T> tells whether there already exists an override of operator<< that
 * supports T.
 */
template <typename, typename = void>
struct can_cout : public std::false_type ;

template <typename T>
struct can_cout<T, std::void_t<decltype(operator<<(std::declval<std::ostream>(), std::declval<T>()))> > : public std::true_type ;

/**
 * Implement operator<< iff GlmType is handled by glm::to_string but there is
 * not already an override of operator<< that hanldes this type.
 */
template<
    typename GlmType,
    typename = std::enable_if_t<!can_cout<GlmType>::value>,
    typename = decltype(glm::to_string(std::declval<GlmType>()))
>
std::ostream& operator<<(std::ostream& out, const GlmType& g)

    return out << glm::to_string(g);

【讨论】:

以上是关于如何打印通过引用传递的 glm::vec3 类型的向量值?的主要内容,如果未能解决你的问题,请参考以下文章

glm::vec3 精度 C++

如何在相机类中添加滚动

glm - 将 mat4 分解为平移和旋转?

为啥 glm::vec3 不像浮动数组那样排序[关闭]

GLM:如何创建一个 9 列和 3 行的矩阵

GLM:获取平面线交点的位置