Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you use an undefined type in a C++ template function if the function is never used?

Tags:

c++

I am trying to create a conversion function between objects of two classes (Eigen::Vector3d and MyVector, a Protocol Buffers message), but I want to delay evaluation of the function body until the function is referenced (at which point both classes would be defined).

The function should be callable in files that later define both classes, and it should not cause a compilation error if the function is never used.

I have:

#include <Eigen/Core> // defines Eigen::Vector3d

class MyVector {
  public: int set_x(int x) { x_ = x; }
  private: int x_;
}

void operator<< (MyVector &msg, const Eigen::Vector3d &vec) {
  msg.set_x(vec.x());
}

which I use as:

MyVector msg;
Eigen::Vector3d vec(1, 2, 3);
msg << vec;

This works fine if the function is defined after MyVector, but I would like to be able to define the function such that it can be included in a translation unit that lacks the MyVector class.

I could change the function to this:

template<typename Msg>
void operator<< (Msg &msg, ...

but this is unacceptable because it would apply to other message classes:

quaternion_msg << Eigen::Vector3d(1, 2, 3);   // quaternion has xyz but also w!

and I want that to cause a build error.

Is there some kind of template magic that can do that? If not, is there a better way to provide this operator short of adding MyVector to the header file (or its dependencies)?

like image 962
user3105361 Avatar asked Dec 15 '13 21:12

user3105361


People also ask

Can templates be used for user defined data types?

Template in C++is a feature. We write code once and use it for any data type including user defined data types. For example, sort() can be written and used to sort any data type items. A class stack can be created that can be used as a stack of any data type.

How will you restrict the template for a specific datatype?

There are ways to restrict the types you can use inside a template you write by using specific typedefs inside your template. This will ensure that the compilation of the template specialisation for a type that does not include that particular typedef will fail, so you can selectively support/not support certain types.

Can a non template class have a template member function?

A non-template class can have template member functions, if required. Notice the syntax. Unlike a member function for a template class, a template member function is just like a free template function but scoped to its containing class.

What is the need of template in c++?

Templates in c++ is defined as a blueprint or formula for creating a generic class or a function. To simply put, you can create a single function or single class to work with different data types using templates. C++ template is also known as generic functions or classes which is a very powerful feature in C++.


2 Answers

You can use undefined types or functions in function templates as long as they depend somehow on a template argument and are defined at the point of instantation: non-dependent names are looked up at the pointer where the function template is defined. Dependent names are looked up at the point of instantiation (assuming two-phase name look-up is correctly implemented).

The other side, preventing successful instantiation with other types than a small set of selected types could probably be done using SFINAE:

class MyVector;
template <typename Msg>
typename std::enable_if<std::is_same<Msg, MyVector>::value>::type
operator<< (Msg& msg, Eigen::Vector3d const& vec) {
    msg.set_x(vec.x);
}

The type of std::enable_if<F, T> is only defined if F is true (and T is defaulted to void). Since std::is_same<Msg, MyVector>::value becomes true only when Msg is MyVector this operator only gets defined when instantiated with MyVector. On the other hand, it gets defined when instantiated a which point MyVector is hopefully defined.

However, since MyVector is named in the interface, its name needs to be declared although it doesn't needed to be defined. It is possible to avoid this need if MyVector could specialize a trait in which case naming MyVector a type can be delayed until it is defined and the trait is specialized instead. Doing something like this may be important if MyVector actually happens be a template with defaulted arguments as these can't be forward declared.

like image 136
Dietmar Kühl Avatar answered Oct 24 '22 11:10

Dietmar Kühl


Create a small templatized class that is specialized and use that within the templatized operator << function.

ie:

template <typename MSG>
struct Convertor;  // generic causes compiler error

template<>
struct Convertor<MyVector> {
  static void Convert(MyVector msg, Eigen::vector3d const& vec) {
    msg.set_x(vec.x());  
  }
};

template<typename Msg>
void operator<< (Msg &msg, const Eigen::Vector3d &vec) {
  Convertor<Msg>::Convert(msg, vec);
}

You can expand this pattern to more template parameters if needed and specialize for only the conversions you want.

like image 1
Michael Avatar answered Oct 24 '22 09:10

Michael