Invalid operands for binary expressions error

I am following a Ray Tracing series to create a custom ray tracer with C++. There are several custom classes that are being created but only two are relevant for this question mostly.

The first one is a vec3 class. The class definition/declarations are in vec3.h and the implementation is in vec3.cpp. Within vec3.cpp are a few "utility" functions. One of them is a "operator*" function which takes a double as the left operand and a vec3 object as the right operand. There's another version of the operator* function which takes the double/vec3 on opposite sides of the * and just calls the previous definition. I am able to compile the vec3 class fine with
 
g++ -c vec3.cpp -I ../include (vec3.h lives in include/)


I have another class "ray" with a method "at" that takes a double "t" as input and returns orig + t*dir (orig/dir are members of ray of type vec3 -- and yes "vec3.h" is included). Whenever I try to compile the ray class, I get an "invalid operands to binary expression ('double' and 'const vec3')" error for that line

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
vec3.h

class vec3 {
...
};
...
using point3 = vec3;

vec3.cpp
#include "vec3.h"
...
inline vec3 operator*(const vec3 &u, const vec3 &v) {
    return vec3(u.e[0] * v.e[0], u.e[1] * v.e[1], u.e[2] * v.e[2]);
}

inline vec3 operator*(double t, const vec3 &v) {
    return vec3(t*v.e[0], t*v.e[1], t*v.e[2]);
}

inline vec3 operator*(const vec3 &v, double t) {
    return t * v;
}
...

ray.h
#include "vec3.h"
class ray {
...
point3 at(double t) const;
...
};
...

ray.cpp
#include "ray.h"
...
point3 ray::at(double t) const {
    return orig + t*dir;    // problem line
}


I have always had a difficult time understanding how compiling with C++ works - I always think I have the basics then something like this comes up. Note also, the implementation here might not be the most efficient, but I am mostly just "copy and pasting" from the tutorial aside from pulling apart the custom classes into their own header/cpp files. I suppose it might work to pull the "utility" functions into the vec3 class, but I'm not sure that will solve this problem
Last edited on
Are the declarations of your operator * functions inside vec3.h? If not then the existence of those functions won’t be known to ray.cpp.
@lastchance

They were not. I think I tried that before but was getting some other difficulties. They are now and that portion is working.

Thanks

I guess I might as well as it here since it should be a small problem -- I can make another post if need be:

main.cpp/ray.cpp use 2 operators and one utility function from vec3. I get a linker error when I try to link everything together after compiling separately:

1
2
g++ -c ray.cpp vec3.cpp -I ../include -w // runs fine
g++ main.cpp ray.o vec3.o -I ../include -w // get undefined symbol errors for the functions inv vec3 


The actual error output if that helps:
1
2
3
4
5
6
7
8
9
10
Undefined symbols for architecture x86_64:
  "unit_vector(vec3)", referenced from:
      ray_color(ray const&) in main.o
  "operator*(double, vec3 const&)", referenced from:
      ray_color(ray const&) in main.o
      ray::at(double) const in ray.o
  "operator+(vec3 const&, vec3 const&)", referenced from:
      ray_color(ray const&) in main.o
      ray::at(double) const in ray.o
ld: symbol(s) not found for architecture x86_64
Last edited on
I seemed to figure it out. The functions were declared as 'inline' and that seemed to be causing the conflict. I'm going to research the why that is the case and leave it open until I do that way anybody who knows why this happens can answer. Or if nobody does and I figure it out, I will write out an explanation

Edit: for what it's worth, the only reason I declared the functions as inline is because that's what the tutorial indicated. Otherwise, I am not really familiar with what it does
Last edited on
If you are going to inline functions do it in the header file, not the source file, when you split your code into header/source files.

I declared the functions as inline is because that's what the tutorial indicated.

What tutorial?

Learn C++'s inline lesson (as well as the tutorial here at CPP) is IMO rather vague/simplistic about inline functions when it comes to doing it in source vs. header files.
https://www.learncpp.com/cpp-tutorial/75-inline-functions/

For tutorial purposes the simple programs they create don't split code into header/source files, so inlining a function in a single source file is "common practice."

The preprocessor does the same thing with any header files in a multiple file project, replacing the includes with the contents of the headers.

Rule of thumb....

If you want a function to be inline'd you have to place it in a header file, unless it's only being used in the same source file. The reason being that the compiler needs the actual function definition in order to place the definition "inline" wherever it's being called, and then compile it up.

https://stackoverflow.com/questions/7883022/inline-in-source-file
This is the tutorial

https://raytracing.github.io/books/RayTracingInOneWeekend.html#rays,asimplecamera,andbackground/therayclass

I'll take a look at the lessons you posted, thanks for your help
Topic archived. No new replies allowed.