[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 233
  • Last Modified:

Using templated arguments to function pointers

For the code below, does a generic solution exist that would allow me to use one 'map' as opposed to creating instances of imap and dmap?  In other words, I'd like to have one function that I'll pass into the map that will take a type T where T could be int, double, etc.

Source code please.  Thanks

# include <iostream>
typedef unsigned int word_type ;
class foo {

public:
 void set_mx_digits_1 ( word_type wt )  {  std::cout << "+" ; }
 void set_mx_digits_2 ( double dt ) {  std::cout << "-"; }

 // etc.
};
typedef void ( foo::*set_mx_digits_1 )( word_type wt ) ;
typedef void ( foo::*set_mx_digits_2 )( double dt ) ;

# include <map>
int main () {

 foo foo_object;
 typedef std::map < int, set_mx_digits_1 > imap;
 typedef std::map < int, set_mx_digits_2 > dmap;

 imap int_map ;
 int_map [ 0 ] = &foo::set_mx_digits_1 ;
 for ( imap::iterator iter = int_map.begin(); iter != int_map.end();
++iter ) {
   set_mx_digits_1 hex = ( *iter ).second;
   ( foo_object.*hex)( 4 ) ;
 }

 dmap double_map ;
 double_map [ 0 ] = &foo::set_mx_digits_2 ;
 for ( dmap::iterator iter = double_map.begin(); iter !=
double_map.end(); ++iter ) {
   set_mx_digits_2 hex = ( *iter ).second;
   ( foo_object.*hex)( 4.5 ) ;
 }
}

0
forums_mp
Asked:
forums_mp
  • 3
  • 3
  • 2
  • +1
2 Solutions
 
Infinity08Commented:
You can group different types into a union, and use that union (preferrably with some type information) as value for the map.
0
 
evilrixSenior Software Engineer (Avast)Commented:
I'm not sure I fully understand what you are trying to do here so forgive me if I've not provided a solution that is completely what you are after, if not we can work on it...

You don't need to name your class member functions different for each type, they can have one name and the compiler will see them as overloaded functions. The problem is you can't take the address of an overloaded function and expect it to behave in an overloaded way (the function pointer needs to be strongly typed). You can get around this by using a small intermediate functor that takes a 'this' pointer and a value, as template parameters, to be passed to the overloaded member function. You can then bind the this pointer to the overloaded member and pass in the type and normal function overloading will happen.

I'm not sure though, what this gains since each map entry contains the same functor. Maybe you could be clearer on what your objective is here as they is probably a much simpler solution.
// scratch.cpp : Defines the entry point for the console application.
//
 
#include "stdafx.h"
 
# include <iostream>
 
typedef unsigned int word_type ;
 
class functor_t
{
public:
	template<typename T, typename U>
	void operator()(T const & obj, U u) const
	{
		obj.set_mx_digits(u);
	}
};
 
class foo
{
public:
	void set_mx_digits ( word_type wt )  const {  std::cout << "+" ; }
	void set_mx_digits ( double dt ) const {  std::cout << "-"; }
};
 
# include <map>
 
int main ()
{
	foo foo_object;
	functor_t functor;
	
	typedef std::map < int, functor_t * > tmap_t;
 
	tmap_t tmap ;
	tmap [0] = &functor;
	
	unsigned int i = 4;
	double d = 4.4;
 
	for (tmap_t::iterator iter = tmap.begin(); iter != tmap.end(); ++iter)
	{
		functor_t const * functor = ( *iter ).second;
		(*functor)(foo_object, i);
		(*functor)(foo_object, d);
	}
}

Open in new window

0
 
Infinity08Commented:
>> Maybe you could be clearer on what your objective is here as they is probably a much simpler solution.

I agree.
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
forums_mpAuthor Commented:
To be frank I'm often not sure how much clearer I can be on my objective but hey my apologies.  Lets try again:  

The file c13v_msg (below) reflects what I'm faced with.  The objective is to test _every_ set/get method within the file c13v_msg.    For instance if I invoke set_header_word with a value of 1.  I'll then call get_header_word and the returned value ought to be 1.

Of course the objective isn't isolated to a c13V_msg file.   I have a litany of cXX_msg files where XX represents a number from 1 to 30 and is representative of incoming messages I'm receiving from an aircraft.

So I'm faced with three problems all surrounding the most efficient way to unit test these files
  a)  I'd hate to sit and manually type up a typedef'd representation of each function, so I wrote a program that read each cXX_msg file and output a typedef'd representation of each function. The program also has the associated bit ranges for each 'set' method.   I then copied the typedef'd representations from the output file to my main program which I'll use to unit test the functions in the cXX_msg files.   This leads me to b.
b) So now I have a litany of typedef'd representation that I copied from the output file in a) above:  i.e

typedef void ( c13v_msg::*set_header_word )( word_type header ) ;
typedef word_type ( c13v_msg::*get_header_word )( ) ;
typedef void ( c13v_msg::*set_mx_digits_1 )( word_type wt ) ;
typedef word_type ( c13v_msg::*get_mx_digits_1 )( ) ;
typedef void ( c13v_msg::*set_mx_digits_2 )( double dt ) ;
typedef word_type ( c13v_msg::*get_mx_digits_2 )( ) ;
// and so on....  
NOTE:  I used 'foo' for simplicity in my initial post above

The path I was headed down seems very inefficient hence my initial post which I wont repeat here again.

c) Most cXX_msg is 60 words, where a word is 16 bits wide.   Not every member functions utilize all 16 bits.  I must now try to determine how to plug in a min/max value for each 'set' method and of course validate the result with the get methods.

In the end, perhaps the approach in a) was my initial downfall heading into b).  I tried to envision a semi automated way to do this but I can't envision how thats possible.





 
# ifndef BASE_MSG_H
# define BASE_MSG_H
 
// filename: cbase_msg.h
# include <iostream>
#include "cushort_bitfields.h" //not shown
 
class cbase_msg {
  int id ;
public:
  cbase_msg( int id_ )
  : id ( id_) 
  {}
  virtual ~cbase_msg(){}
  cushort_bitfields  mdata_word[ 30 ];
 
  int get_id() const { return id; } 
};
 
# endif 
 
 
// filename c13v_msg.h
 
# ifndef C13V_MSG_H
# define C13V_MSG_H
 
# include "base_msg.h"
 
class c13v_msg : public cbase_msg {
public:
  static int const ID = 13 ;
public:
  c13v_msg()
  : cbase_msg( ID ) 
  {}
 
  ~c13v_msg(){}
 
  inline void set_header_word    ( word_type header ); 
  inline word_type get_header_word () ; 
 
  inline void set_mx_digits_1  ( word_type wt ); 
  inline word_type get_mx_digits_1 (); 
 
  inline void set_mx_digits_2  ( double dt ); 
  inline double get_mx_digits_2 (); 
 
  inline void set_list1_tgt_north        ( word_type tgt_north ); 
  inline word_type get_list1_tgt_north (); 
 
  inline void set_list1_tgt_east        ( word_type tgt_east ); 
  inline word_type get_list1_tgt_east (); 
 
  inline void set_list1_tgt_down        ( word_type tgt_down ); 
  inline word_type get_list1_tgt_down (); 
 
  inline void set_list1_status_flag        ( word_type status_flag ); 
  inline word_type get_list1_status_flag (); 
 
  // LOTS MORE
  //void set_checksum       ( word_type checksum ); 
  //void get_checksum       (); 
 
};
 
// header - word 0
void c13v_msg::set_header_word( word_type header )  {
  data.mdata_word[ 0 ].SetBits ( 0, 15, header ); 
}
word_type c13v_msg::get_header_word()   {
  return ( data.mdata_word[ 0 ].GetBitsValueActual( 0, 15 ) ) ; 
}
 
// mx_digits 1 - word 1
void c13v_msg::set_mx_digits_1( word_type wt )  {
  data.mdata_word[ 1 ].SetBits ( 0, 15, wt ); 
}
word_type c13v_msg::get_mx_digits_1()   {
  return ( data.mdata_word[ 1 ].GetBitsValueActual( 0, 15 ) ) ; 
}
 
// mx_digits 2 - word 2
// list1_tgt_north - word 3 
// and so on
 
#endif

Open in new window

0
 
evilrixSenior Software Engineer (Avast)Commented:
Function pointers are strongly typed so you can't just dump different pointers into a generic container as their static types will all be different. The compiler needs to know, at compile time, what the static types are so the only way to dynamically change what function is being called is to write code to call the correct function based upon a runtime value. You'd have to implement, for example, a switch statement to direct control to the correct member function.
0
 
itsmeandnobodyelseCommented:
>>>> Function pointers are strongly typed so you can't just dump different pointers into a generic container as their static types will all be different.

You could cast the function pointer to some basic function type. That way you could store different function pointers in the map. However, the function that iterates thru the map must know the correct type in order to make a proper recast. Though casting is not the most recommendable thing in C++, it is a often used means to store function pointers with different arguments in a container. E. g. MFC does it that way with message and event mapping to customized function pointers.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> However, the function that iterates thru the map must know the correct type in order to make a proper recast
But doesn't that then miss the whole point of the question? It's not a generic solution because you need to know what type to cast back to and you'll need to write specific code to perform that cast. This is no different from just having a switch that chooses what function to call.
0
 
itsmeandnobodyelseCommented:
>>>> But doesn't that then miss the whole point of the question?
It can but is must not . The type of the function pointer can be stored in some associated container (like a factory), or - as it is with MFC message maps - the target object was an instance of a derived class, hence when the function pointer was invoked it could be casted to the appropriate type by means of an overloaded virtual function (in MFC it is made by using macros like ON_COMMAND, ON_MESSAGE, ON_NMCLICK) which indeed *knows* what function type and what arguments were required.
0
 
itsmeandnobodyelseCommented:
Note, I personally do not recommend the casting of function pointers. I think you can have a function prototype with a pointer (or reference) to a baseclass, where each individuell function can pass a pointer of a derived class, thus adding any arguments you want to functions using the same prototype.
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 3
  • 3
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now