Question

I have a sanitization function that I want to run on (traditional) pointer types only.

My problem is with function templates I can get as far as limiting the function to only pointers, however because of casting rule differences between function pointers and regular pointers, I run into problems.

The Sanitize() function needs to run against a whole slew of types, some of which are pointers and need to be sanitized, others of which are function pointers of varying arity and parameter types and should not be sanitized, and some of which are non-pointer data types which also should not be sanitized.

Anything obvious I'm missing?

  template<typename T>
  T* Sanitize(T* value)
  {
     return (T*)SanitizePointer(value);  //SanitizePointer returns void*, so cast is necessary
  }

  template<typename T>
  T Sanitize(T value)
  {
     return value;  //Non-pointers can be passed without sanitization
  }

  int main()
  {

     int  a;
     int* b;
     int (*c)();

     Sanitize(a);
     Sanitize(b);
     Sanitize(c);   //<- ERROR

     return 0;
  }
Was it helpful?

Solution

While this problem could be solved manually, its easiest to utilize Boosts type traits and SFINAE helper to selectively disable the overload for pointers if T* is a function pointer:

template<typename T>
typename boost::disable_if<boost::is_function<T>, T*>::type
Sanitize(T* value)
{
    // ...
}

OTHER TIPS

How about this? Tested online using Comeau C/C++.

void* SanitizePointer( void* p ) 
{ return p; }

void _Sanitize( ... ) 
{
}

void _Sanitize( void* p )
{
    SanitizePointer( p );
}

// making this a ref so as to avoid the copy, YMMV
template<typename T>  
T& Sanitize(T& value) 
{     
    _Sanitize(value);
    return value;
}  

int main(int argc, char* argv[])
{
    int  a;
    int* b;
    int (*c)();
    Sanitize(a);
    Sanitize(b);
    Sanitize(c);
    return 0;
}

Am I missing something? The following code compiles fine ( on VS2008)

void* SanitizePointer(void* value)
{
    return (void*)0;
}

template<typename T>
  T* Sanitize(T* value)
  {
     return (T*)SanitizePointer(value);  //SanitizePointer returns void*, so cast is necessary
  }

  template<typename T>
  T Sanitize(T value)
  {
     return value;  //Non-pointers can be passed without sanitization
  }

  int main()
  {

     int  a;
     int* b;
     int (*c)();

     Sanitize(a);
     Sanitize(b);
     Sanitize(c);   //<- Compiles fine

     return 0;
  }

As an explanation: you are trying to create a partial specialization of a function template. C++ just doesn’t allow that, full stop. Partial specializations only exist for class templates.

gf has posted the solution: use SFINAE (preferably via Boost).

I met similar problem in g++. I solved on a standard way, but I knew the possible function signatures. What I did, I created some template specialization for the possible function pointers.

#include <cxxabi.h>
#include <iostream>
using std::cout;
using std::endl;
...

#define O cout << __PRETTY_FUNCTION__ << endl;

// Return the user-readable type name
//#if defined(__GNUC__) || defined(__GNUG__)
#define _TYPENAME(x) typeid(x).name()
#define TYPENAME(x) abi::__cxa_demangle(_TYPENAME(x), 0, 0, 0)

// Show type information for variables and type names as well
#define OTYP(x) cout << "(" << #x << ") <" << TYPENAME(x) << ">    '" << _TYPENAME(x) << "'" << endl;
#define OVAL(x) cout << #x << " = " << x << ", <" << TYPENAME(x) << ">    '" << _TYPENAME(x) << "'" << endl;

template <class T> void typ(T o()) { O; cout << "f "; OTYP(T); } 
template <class T, class U> void typ(T o(U)) { O; cout << "F "; OTYP(T); OTYP(U); }
template <class T> void typ(T o(...)) { O; cout << "e "; OTYP(T); }

const char* testcs(const std::string& s) { return s.c_str(); }
void testv(const std::string& s) { }    
void testvv() {}
void testvV(void) {}                                                            
void teste(...) { }

int main() {
  typ(testcs);
  typ(testv);
  typ(testvv);
  typ(testvV);
  typ(teste);
}

Output:

void typ(T (*)(U)) [with T = const char*, U = const std::string&]
F (T) <char const*>    'PKc'
(U) <std::string>    'Ss'

void typ(T (*)(U)) [with T = void, U = const std::string&]
F (T) <void>    'v'
(U) <std::string>    'Ss'

void typ(T (*)()) [with T = void]
f (T) <void>    'v'

void typ(T (*)()) [with T = void]
f (T) <void>    'v'

void typ(T (*)(...)) [with T = void]
e (T) <void>    'v'

I hope I could help...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top