0

I have a class that wraps logic for matrix management. Meanwhile I have a set of methods specialized in handling some important time spending matrix manipulation operations (like LU factorization and so on).

The class uses the functions defined in that file. That file needs to have access to that class' elements. I need to make those specialized methods friends of the above-mentioned class. This causes me to include one header in each other header.

My problem

The situation I described before is coded here as follows. The first code refers to mat.hpp.

#ifndef MAT_HPP
#define MAT_HPP
#include "operations.hpp"
namespace nsA {
template <typename T>
// Templated class because matrices can be real or complex
class mat {
   // Members...
   friend template <typename U> 
   void exec_lu(const mat<U>& in, const mat<U>& out);
   // Members...
} /* class end */
}
#endif
#endif

The second file is operations.hpp

#ifndef OPERATIONS_HPP
#define OPERATIONS_HPP
#include "mat.hpp"
namespace nsA {
namespace nsB {
template <typename T>
void exec_lu(const mat<T>& in, const mat<T>& out);
}
}
#endif

The problem is that the compiler starts complaining.

Note

Consider please that if I comment the friend declaration in mat.hpp but leave the inclusions, the compiler tells me that in 'operations.hpp' type mat is not defined!

If also comment the inclusion in mat.hpp and keep friend declaration commented as well, the compiler is ok!

How to work on this?

Thankyou

Community
  • 1
  • 1
Andry
  • 16,172
  • 27
  • 138
  • 246

2 Answers2

2

You can do this by just adding a couple of forward declarations... But you can even do better with a bit more code:

template <typename T> class mat;
template <typename T> void exec_lu( const mat<T>&, const mat<T>& );
template <typename T>
class mat {
   friend void exec_lu<T>( const mat<T>&, const mat<T>& );
};
template <typename T>
void exec_lu( const mat<T>& a, const mat<T>& b ) { ... }

The main difference between this approach and yours (other than fixing the syntax limitations) is that in this approach a single instantiation of exec_lu is granted access to mat<T>, in particular the instantiation that needs access to it. In your code (after fixing), all specializations of exec_lu would have access to any specialization of mat (i.e. exec_lu<int> could access mat<int> private members, but also mat<double>...) and you probably don't want that.

For a longer description of the different options to declare friends of a template, read this answer to a related question.

Community
  • 1
  • 1
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • FANTASTIC!!! Not only you answered my question, but answered to the one I wanted to do ask next!!! David you are awesome!!!! Thank you very much, thank you! – Andry Jun 29 '12 at 04:25
1

To get this to work, you need to forward declare the class. It looks like this:

The file mat.hpp:

#ifndef MAT_HPP
#define MAT_HPP
namespace nsA {
template <typename T>
class mat;
namespace nsB {
  template <typename T> 
  void exec_lu(const mat<T>& in, const mat<T>& out);
}
template <typename T>
class mat {
   friend void exec_lu(const mat<T>& in, const mat<T>& out);
};
}
#endif

And the file operations.hpp:

#ifndef OPERATIONS_HPP
#define OPERATIONS_HPP
#include "mat.hpp"
namespace nsA { namespace nsB {
template <typename T>
void exec_lu(const mat<T>& in, const mat<T>& out);
}}
#endif

Your original declaration gives out more friendship than mine. Mine only grants friendship to the function that matches the typename of the class.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
Jerome
  • 1,429
  • 11
  • 13
  • I have reformatted the code (use `Ctrl-K` or the *code* button in the editor rather than `
    ` html tags --alternatively indent each code line with enough spaces). Also removed whitespace and comments --screen real state is limited in the web page.
    – David Rodríguez - dribeas Jun 29 '12 at 03:33