views:

402

answers:

4

(C++) 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;
  }
A: 

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;
  }
Phillip Ngan
The question was how to let `Sanitize(T)` be called instead of `Sanitize(T*)` if `T*` is a function pointer.
Georg Fritzsche
It doesn't compile with any other compiler.
UncleBens
For instance, try it out on codepad.org. You get this: In function 'T* Sanitize(T*) [with T = int ()()]':t.cpp:28: instantiated from hereLine 9: error: invalid conversion from 'int (*)()' to 'void*'compilation terminated due to -Wfatal-errors.
Joe Schneider
You are correct about the above code not compiling on comeau and codepad. I will remember to compile C++ snippets with something other than VS in future!
Phillip Ngan
The Boost is_function headers actually have a comment about how "some compilers incorrectly allow a conversion from function pointers to void*". They were frustrated by this as well, since a standards conforming compiler would have allowed their implementation to be much simpler.
Joe Schneider
+4  A: 

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)
{
    // ...
}
Georg Fritzsche
It seems a bit simpler with: `typename boost::disable_if<boost::is_function<T>, T*>::type`
UncleBens
Point taken, thanks.
Georg Fritzsche
Awesome, thanks!
Joe Schneider
A: 

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).

Konrad Rudolph
+2  A: 

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;
}
smocoder
Wow! With the (...) trick (didn't think of this!) you don't even need the template. Seems even better that the boot SFINAE solution. I'll try it out and give you credit for the answer if it works in my real application.
Joe Schneider