2

I saw a video about templates in c++ the other day and it had the following code:

template <typename T>
void someFunction(T num) {
   Print(num);
}

The "Print()" just prints out the var "num" in console. I basically understood how to use templates as parameters. However, I don’t know how to use this with Structs, or if it’s even possible. I mean something like this:

struct vec2 {
   float x, y;
};

struct vec3 {
   float x, y, z;
};

template <typename T>
void someFunction(T vec);

I want to check in the function whether "vec" is a vec2 or a vec3 and then use it differently. Like this:

if (vec==vec2) {
   //Print x and y
else if (vec==vec3) {
   //Print x, y and z
}

In the end my goal is simply to have a function that I can give 2 different structures to. I already heard about std::is_same and tried it but without any success.

cigien
  • 57,834
  • 11
  • 73
  • 112
  • 2
    What is `Print`? Do you know what "overloading" is? That might be more suitable than templates for what you're trying to achieve. – cigien Dec 10 '20 at 19:19
  • 1
    `Print` would have to know how to display the contents of the structure or anything else used at the template argument. Maybe it itself is a template. Maybe it has overloads. Or maybe it just fails to compile because it can't handle the type. – user4581301 Dec 10 '20 at 19:21
  • I've rolled back your edit. Please don't modify your question once you receive answers. You can always ask another question if you want. – cigien Dec 10 '20 at 20:29
  • @cigien Ok, thanks for letting me know. – Hydrated Dragon Dec 10 '20 at 20:33

2 Answers2

4

This is actually possible using a type trait and if constexpr:

#include <iostream>
#include <type_traits>

struct vec2 {
   float x, y;
};

struct vec3 {
   float x, y, z;
};

template <typename T>
void someFunction(T vec)
{
   if constexpr (std::is_same_v<T, vec2>) {
      std::cout << vec.x << ' ' << vec.y << '\n';
   }
   else if constexpr (std::is_same_v<T, vec3>) {
      std::cout << vec.x << ' ' << vec.y << ' ' << vec.z << '\n';
   }
}

int main()
{
    vec2 v2 = {1, 2};
    vec3 v3 = {3, 4, 5};
    
    someFunction(v2);
    someFunction(v3);
}

(N.B. prior to C++17, you'll need std::is_same<T, vec2>::value.)

That being said, in your example, a simple set of function overloads would be more appropriate:

#include <iostream>

struct vec2 {
   float x, y;
};

struct vec3 {
   float x, y, z;
};

void someFunction(vec2 vec) {
   std::cout << vec.x << ' ' << vec.y << '\n';
}

void someFunction(vec3 vec) {
   std::cout << vec.x << ' ' << vec.y << ' ' << vec.z << '\n';
}

int main()
{
    vec2 v2 = {1, 2};
    vec3 v3 = {3, 4, 5};
    
    someFunction(v2);
    someFunction(v3);
}

In both cases, you may wish to consider taking the object by const reference instead of by value (which will copy it).

Justin
  • 24,288
  • 12
  • 92
  • 142
Asteroids With Wings
  • 17,071
  • 2
  • 21
  • 35
0

The answer from Asteroids With Wings gives two solutions, and the second of these is probably what you want. But the first is definitely not; you can achieve the same functionality simply by using function template specialisation:

#include <iostream>

struct vec2 {
   float x, y;
};

struct vec3 {
   float x, y, z;
};

template <typename T>
void someFunction(T vec) ;

template<>
void someFunction<>(vec2 vec)
{
   std::cout << vec.x << ' ' << vec.y << '\n';
}

template<>
void someFunction<>(vec3 vec)
{
   std::cout << vec.x << ' ' << vec.y << ' ' << vec.z << '\n';
}

int main()
{
    vec2 v2 = {1, 2};
    vec3 v3 = {3, 4, 5};
    
    someFunction(v2);
    someFunction(v3);
}
TonyK
  • 16,761
  • 4
  • 37
  • 72