Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

C++: how to test if an instance of a class contains a given member in a template function?

C++: how to test if an instance of a class contains a given member in a template function?

I googled this, looked over examples that are supposed to work… But still don’t understand why?!…

The first thing I could have thought of is using traits and template specialization, seems this doesn’t work.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Indeed, this is OK:

>> cat main.cpp 
#include <iostream>
#include <type_traits>

struct point2D {
    double x = 0.;
    double y = 0.;
};

struct point3D {
    double x = 0.;
    double y = 0.;
    double z = 0.;
};

template <typename T> struct has_z : std::false_type {}; // default case.
template <> struct has_z<point3D> : std::true_type {}; // specialized case.

template<typename T> void print(T const & obj) {
  std::cout << obj.x << " " << obj.y;
  //if (has_z<T>::value) std::cout << obj.z;
  std::cout << std::endl;
};

int main() {
  point2D pt2D;
  print(pt2D);
  point3D pt3D;
  print(pt3D);
}

>> g++ -o main main.cpp
>> ./main 
0 0
0 0

But, uncommenting the commented line gives:

>> g++ -o main main.cpp 
main.cpp: In instantiation of ‘void print(const T&) [with T = point2D]’:
main.cpp:27:8:   required from here
main.cpp:21:41: error: ‘const struct point2D’ has no member named ‘z’
   21 |   if (has_z<T>::value) std::cout << obj.z;
      |                                     ~~~~^

What is the minimal change to get this to work (with C++20) and why?

>Solution :

You need to use:

template<typename T> void print(T const & obj) {
  std::cout << obj.x << " " << obj.y;

  if constexpr(has_z<T>::value) std::cout << obj.z;

  std::cout << std::endl;
};

That way, the compiler knows the expression is a compile-time constexpr and can remove the .z read. Otherwise, the if is runtime and the compiler can’t generate one possibility (the read of .z, never mind it would never happen to run)

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading