61

I have a small obj loader and it takes two parameters and passes them back to the input variables.. however this is my first time doing this and i'm not sure how to print said values now. Here is my main function to test if the loader is working. I have two vectors of type glm::vec3 to hold the vertex and normal data.

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;   
}

The line commented above is what is generating useless info. If I leave it like that and run the program I get a bunch of errors spewed at me (too unformatted and long to paste here) and if I add the reference operator I get output like this:

0x711ea0
0x711eac
0x711eb8
0x711ec4    // etc

Any idea what I am doing wrong?

iKlsR
  • 2,642
  • 6
  • 27
  • 45
  • 3
    Does `glm::vec3` overload `operator<<`? If not, you're probably better printing, for example, `vertices[i].x << ' ' << vertices[i].y << ' ' << vertices[i].z` – chris Jul 17 '12 at 03:06
  • that was one of the many garbled errors i saw in the ouput window? i don't know if it does. – iKlsR Jul 17 '12 at 03:06
  • What output are you expecting from it? I've never heard of the class itself, but each member might be what you want. You can overload it yourself to do that, too. – chris Jul 17 '12 at 03:08
  • similar errors when i try that @Lwin – iKlsR Jul 17 '12 at 03:08
  • 2
    show us the definition of glm:vec3. – Alanmars Jul 17 '12 at 03:09
  • Oh, and that "reference operator" is actually the address-of operator. It's used to get the address of an rvalue (the output you see is the address of each `vertices[i]` in memory), whereas a reference would be applied to a declared variable, such as in a function header. Same symbol, different meanings. – chris Jul 17 '12 at 03:25
  • It gets the address of an lvalue. In fact, one of the simplest definitions of rvalue is that `operator&` won't apply to them. – Puppy Jul 17 '12 at 03:50
  • 1
    @DeadMG, Oops, I meant lvalue :p Of course you don't go around `&5`, `&"hi"` etc. – chris Jul 17 '12 at 13:56
  • 1
    @iKlsR The answer to your other question about printing floats is `std::copy(std::begin(verts),std::end(verts),std::ostream_iterator(std::cout, " "));` – bames53 Jul 17 '12 at 16:55
  • OK so chris found it already... for "general reference" aka let me websearch that for you... got you this close: https://glm.g-truc.net/0.9.8/api/a00127_source.html#l00461 hope it helps. – n611x007 Jan 24 '17 at 23:16

6 Answers6

137

glm has an extension for this. Add #include "glm/ext.hpp" or "glm/gtx/string_cast.hpp"

Then to print a vector for example:

glm::vec4 test;
std::cout<<glm::to_string(test)<<std::endl;
iKlsR
  • 2,642
  • 6
  • 27
  • 45
user2103388
  • 1,386
  • 1
  • 9
  • 2
22

I think the most elegant solution might be a combination of the two answers already posted, with the addition of templating so you don't have to reimplement the operator for all vector/matrix types (this restricts the function definition to header files, though).

#include <glm/gtx/string_cast.hpp>

template<typename genType>
std::ostream& operator<<(std::ostream& out, const genType& g)
{
    return out << glm::to_string(g);
}
JAB
  • 20,783
  • 6
  • 71
  • 80
  • 1
    Out of curiosity: what about your templating stops this function from being used with types other than the glm ones? – Ludwik Aug 06 '15 at 05:06
  • 2
    This only gives me "ambiguous overload". – Ludwik Aug 06 '15 at 05:50
  • @Ludwik Nothing other than judicious placement of the template and preexisting template specializations of `operator<<`, unfortunately, but I had little experience with SFINAE techniques at the time (still don't, for that matter) so I'll leave that exercise to someone with more experience than me. `operator<<` is generally specialized for built-in types, though, so as long as you aren't using it with classes/structs/etc. you haven't already defined a specialization for you should be okay normally. If you're getting "ambiguous overload", it means something else has a general overload for `<<`. – JAB Aug 06 '15 at 13:38
  • If I'm not mistaking something, I'm getting the "ambiguous overload" for `string`. – Ludwik Aug 09 '15 at 05:12
  • As far as I can tell at this point, SFINAE should make it so that the provided template is only selected when a valid parameter is supplied to `glm::to_string()`, as otherwise the template should fail to compile (which should result in another template version being chosen). You may be including an overload/specialization of `operator<<` that takes a `const std::string &` as its second parameter somewhere. – JAB Jan 12 '16 at 15:59
  • 2
    SFINAE only works if one of the template parameters fails to expand. To solve ambiguous overloads, include `` and ``, then use `template ()))>` – Cory Sep 11 '17 at 19:14
16

glm::vec3 doesn't overload operator<< so you can't print the vector itself. What you can do, though, is print the members of the vector:

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

Even better, if you use that a lot, you can overload operator<< yourself:

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

    return out;
}

Then to print, just use:

std::cout << vertices[i];
iKlsR
  • 2,642
  • 6
  • 27
  • 45
chris
  • 60,560
  • 13
  • 143
  • 205
  • Hey, if I have a large, multi-file project, where can I put that overload so it becomes usable everywhere? – Ludwik Aug 03 '15 at 08:20
  • 1
    @Ludwik, Pretty please use the extension mentioned in the other answer (this answer works more generally, but I lack knowledge of this library). If you need an overload like this for something, it works like any other class or function you'd use repeatedly. Put a declaration for it into a header and either define it in the header as `inline` to satisfy linking or define it in one implementation file. – chris Aug 05 '15 at 04:05
  • I do use the accepted answer's extension, but it requires calling `glm::to_string` over the vector, while I'd prefer an `<<` overload. Thanks, I'll put it in a header file. – Ludwik Aug 05 '15 at 07:23
  • 2
    It's probably better to put it in terms of what glm provides: `operator <<(...) { return out << glm::to_string(vec); }` – lmat - Reinstate Monica Jan 11 '16 at 22:42
  • @LimitedAtonement, I agree. I was unaware that this function existed until the first other answer was written. At least the answer might still be useful in certain scenarios. – chris Jan 12 '16 at 00:38
  • @chris I've found that the functions are not discoverable at all! – lmat - Reinstate Monica Jan 13 '16 at 02:18
  • never underestimate the power of URLs pointing to https://glm.g-truc.net/0.9.8/api/a00127_source.html#l00461 – n611x007 Jan 24 '17 at 23:18
  • The problem with the other answer is that matrices are printed in a format not really easy to understand on a glance: the columns(!) are printed in a horizontal fashion, one after another in a single line. So I think this answer still has its merit: you can print the matrix in the format _you_ need, not the one suggested by `glm::gtx::string_cast`. – Ruslan May 07 '17 at 13:14
13

GLM has operator<<() in <glm/gtx/io.hpp>

#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;
}

Output is:

[    1.000,    2.000,    3.000]
Grumbel
  • 6,585
  • 6
  • 39
  • 50
0

To get the overload resolution right, you can do something like:

// 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);
}

0

Elaborating on JAB's answer, I use the following to avoid 'operator <<' is ambiguous errors:

#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);
}
Lithy
  • 817
  • 12
  • 23