How to disable implicit conversion to pointer-to-void in parameter overload resolution?

Motivation

Suppose that I have a function taking void * as an argument. I'd like to overload this function to other pointer types, but disable the implicit conversion from other pointer types to void * (and only that conversion). I still want the implicit conversion to base class types to succeed.

class Base {};
class Derived : public Base {};
class Other {};
class Stream {};

Stream & operator<<(Stream&, void *);
Stream & operator<<(Stream&, const Base*);

void test() {
  Stream str;
  Derived der;
  Other other;
  // I want the below to work
  str << (void*)&der;
  str << &der; // (&der) gets implicitly converted to const Base*
  // But I want this to fail at either compile or link time
  str << &other;
}

The Pedantic Pointer Idiom

Prevention of implicit conversion to pointer-to-void has been called a Pedantic Pointer Idiom by Matt Wilson, and it's useful when implementing type-safe streams and logging.

His implementation uses a template facade that dispatches to am implementation with a dummy pointer-to-pointer argument. This leverages the fact that Foo** is not implicitly convertible to void**. I'd like to avoid the overhead of the second argument.

template <typename T> Stream & operator<<(Stream & s, T const* t)  
{  
  return dump(s, t, &t);
} 

Upvotes: 0

Views: 265

Answers (1)

One way of solving it is to specialize the operator for the void type. That way there's no need to declare Stream & dump(Stream &, void const*), thus side-stepping the problem.

template <typename T> Stream & operator<<(Stream & s, T const* t)  
{  
  return dump(s, t);
} 

template <> Stream & operator<<(Stream & s, void const * t)
{
  // implement the dump here
  return s;
}

Upvotes: 1

Related Questions