Click here to Skip to main content
15,889,281 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I need to create a template (non-member) function with two implementations for a multi-threaded delegate connection system.
The chosen implementation needs to be determined by the cv qualifier of the last template parameter which expects a (non-type) member function pointer type.

This sounds like overloading, but the template parameter is not used in the function parameter list so this doesn't apply.
It might be solved by specialization except that the (non-type) member function pointer type is not the only template parameter and template functions don't support partial specialization!

Here's an example:

C++
// Define Source with 1 parameter
template<typename R, typename P>
struct Source
{
	typedef R (*FunctionType) (void*, P);
	FunctionType pRetargetingFunction;
	void* m_pTarget;

	// Call the Source....which calls the retargeting function....which calls the target function
	R operator()(P a)
	{
		return pRetargetingFunction( m_pTarget, a );
	}
};



// Define a Targeter with 1 parameter which defines the ReTargeting Function
template<typename R, typename T, typename P, R (T::*TargetFunction)(P)>
struct Targeter
{
	// define the static Retargeting Function
	static R RetargetFunction( void* pTarget, P a)
	{
		// Store the Result
		R Result;
		T* pTargetObject = static_cast<t*>(pTarget);

		// Lock the target
		pTargetObject->Lock();	// ConstTargeter calls pTargetObject->Shared_Lock();

		// Call the target function   
		Result = (pTargetObject->*TargetFunction)(a);

		// Unlock the target
		pTargetObject->Unlock();

		// Return Result
		return Result;
	}
};



// Connect for non-const Member Function
template<typename R, typename T, typename P, typename R (T::*TargetFunction)(P)>
void Connect(Source<r,>* pSource, T* pTarget)
{
	pSource->m_pTarget = pTarget;
	pSource->m_pRetargetingFunction = &Targeter<r,>::RetargetFunction;
	return;
};




They differ only in the const-ness of the last template parameter and the type of Targeter used to generate the Source Retargeting function (which implement different locking policies: exclusive locking for non-const member functions and shared locking for const member functions).

The only workaround I have found is to use different function names (Connect and ConstConnect), but I don't want the user's of the code to have to look up the const-ness of the targeted member function.

I've looked at the boost::Is_const struct, but can't get my head around how to make a typedef/selector to use the result (and don't know if it will handle the const-ness of a member function pointer type).

Anyone have a solution or ideas to pursue ?
Posted
Updated 10-Oct-11 2:21am
v5
Comments
André Kraak 9-Oct-11 8:18am    
Edited question:
Added pre tags
Spelling/Grammar
WodgerDodger 9-Oct-11 18:32pm    
Thanks for the info Andre and for fixing up the code.

Unfortunately it was still a bit mangled, so I have updated the code just as a plain text paste - not pretty, but the preview looks like template params have been preserved etc.

The target (object) pointer is stored internally in the Source as a void pointer (The source has no visibility of the type it is connected to).
While this screams "Horrible Hack", type safety is restored by the targeter.

The targeter (created by the Connect function) has a static Retargeting function which takes the same parameters as the target function and a (void) pointer to the target.
Type safety is restored by the retargeting function which static_casts the target pointer back to the connected type (compile-time check of target type).
Then the Retargeting function has the Target type and the member function pointer so it can call the target function with the arguments provided to it.

I hope that makes it a little clearer.

What I think I need is a technique that will let me distinguish between a const and non-const member function pointer type at template instantiation ?

Cheers.

Stefan_Lang 10-Oct-11 8:24am    
Added the pre tags again and replaced the angular brackets in template declarations with the appropriate hypertext macros (the pre tag doesn't take well to template argument declarations...)

1 solution

Your source pointer type must depend on the target pointer type because the pRetargetingFunction depends on the target pointer type. An explicit cast is not useful for template pointers.
example:
C++
#pragma once
#include <stdio.h>
#include <tchar.h>

template <typename T>
class Targeter
{
public:
  static void  RetargetFunction(T* p,const TCHAR* name)
  {
    _tprintf(__T("Targeter(%s)\r\n"),name);
  }
};

template <typename T>
class ConstTargeter
{
public:
  static void  RetargetFunction(const T* p,const TCHAR* name)
  {
    _tprintf(__T("ConstTargeter(%s)\r\n"),name);
  }
};

/////////////////////////////////////////////
// Connect for non-const Member Function template
template <typename Source,typename T>
void Connect(Source* pSource, T* pTarget)
{
  pSource->m_pTarget = pTarget;
  pSource->pRetargetingFunction = &Targeter<T>::RetargetFunction;
  return;
}

// Connect for const Member Function template
template <typename Source,typename T>
void Connect(Source* pSource,const T* pTarget)
{
  pSource->m_pTarget = pTarget;
  pSource->pRetargetingFunction = &ConstTargeter<T>::RetargetFunction;
  return;
}
/////////////////////////////////////////////

template <class T>
class tSourceA
{
  typedef void  (*RETARGET)(T*,const TCHAR*);
  static void  intern(T* p,const TCHAR* name)
  {
    _tprintf(__T("internA(%s)\r\n"),name);
  }
public:
  tSourceA(){ m_pTarget=0; pRetargetingFunction=&tSourceA::intern; }
  ~tSourceA(){ pRetargetingFunction(m_pTarget,__T("tSourceA")); }
  T*        m_pTarget;
  RETARGET  pRetargetingFunction;
};

template <class T>
class tSourceB
{
  typedef void  (*RETARGET)(T*,const TCHAR*);
  static void  intern(T* p,const TCHAR* name)
  {
    _tprintf(__T("internB(%s)\r\n"),name);
  }
public:
  tSourceB(){ m_pTarget=0; pRetargetingFunction=&tSourceB::intern; }
  ~tSourceB(){ pRetargetingFunction(m_pTarget,__T("tSourceB")); }
  T*        m_pTarget;
  RETARGET  pRetargetingFunction;
};

int _tmain(int argc, _TCHAR* argv[])
{
  { // example A: not const
    tSourceA<int>    x;
    int              ai[]={1,2,3};

    Connect(&x,ai);
  }
  { // example A: with const
    tSourceA<const int>    x;
    const int              ai[]={1,2,3};

    Connect(&x,ai);
  }
  { // example B: not const
    tSourceB<char>        x;
    char                  ai[]={'1','2','3'};

    Connect(&x,ai);
  }
  { // example B: with const
    tSourceB<const char>  x;
    const char            ai[]={'1','2','3'};

    Connect(&x,ai);
  }

  _gettch();  
  return 0;
}

result:
<br />
Targeter(tSourceA)<br />
ConstTargeter(tSourceA)<br />
Targeter(tSourceB)<br />
ConstTargeter(tSourceB)<br />

You cannot mix none const source classes with const target types and vice versa. Because the retargeting function depends on the target type.
i hope i could help.
regards.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900