Подстановка пустоты как параметра в шаблонный метод

В моем коде у меня есть класс, который регистрирует методы других классов:

#include <iostream>
using namespace std;

template< typename C>
  class Reg {
  public:
    template< typename R, typename A>
      void register_f( string name, R ( C:: *method_p ) ( A)) { /*registration process*/ }

//    template< typename R>
//      void register_void_f( string name, R ( C:: *method_p ) ( void)) { /*registration process*/ }
  };

  class A {
  public:
      int f( void) { return 1; }
      void g( int x) { /* some code*/ }
  };


  int main() {
      Reg< A> r;

      r.register_f( "g", &A::g);
/*1*///  r.register_f( "f", &A::f);
/*2*///  r.register_f< int, void>( "f", &A::f);
/*3*///  r.register_void_f< int>( "f", &A::f);

      return 0;
  }

http://ideone.com/X8PNLC

Раскомментированная строка /* 2 */ выдает ошибку:

Сбой вывода / замены аргумента шаблона:

При замене 'шаблона void register_f(std::string, R (C::*)(A)) [с R = R; A = A; C = A] [с R = int; A = void] ':

ошибка: неверный тип параметра 'void'

Строка / * 1 / совпадает с / 2 * /, но с не очень информативным сообщением об ошибке.

Я понимаю, что для решения проблемы я могу использовать метод register_void_f, но я не хочу этого делать, потому что register_f является частью моего окончательного API.

Вопрос> Как исправить ошибки компиляции, не вводя register_void_f?

У меня есть идея решить эту проблему с помощью частичного специализированного register_f, но я не знаю, как это сделать, поскольку в C++ нельзя частично специализировать шаблонный метод.

PS> Я не могу использовать C++11.

3 ответа

Решение

Перегрузите вашу функцию:

void foo( int ) {}
double bar() { return 3.14; }

template< class R, class A >
void test(  R ( *method_p ) (A)) {  }
template< class R >
void test(  R ( *method_p ) ()) {  }

int main(){
  test(foo);
  test(bar);
}

живой пример

Преобразование этого в методы должно быть простым.

Не использовать void без аргументов ничего не используйте - как-то так:

template< typename R>
     void register_void_f( string name, R ( C:: *method_p ) ()) { /*registration process*/ }

Вы можете использовать следующее:

template< typename C> class Reg;

template <typename C, typename F> struct helper;

template <typename C, typename R, typename A>
struct helper<C, R (C::*)(A)>
{
    void operator() (Reg<C>& reg, const std::string& name, R (C::*method)(A)) const { /* Your implementation */}
};

template <typename C, typename R>
struct helper<C, R (C::*)()>
{
    void operator() (Reg<C>& reg, const std::string& name, R (C::*method)()) const { /* Your implementation */}
};


template< typename C>
  class Reg {
  public:
    template< typename F>
      void register_f(const std::string& name, F method) { helper<C, F>()(*this, name, method);  /*registration process*/ }

  };

И используйте это так:

Reg< A> r;

r.register_f( "g", &A::g);
r.register_f( "f", &A::f);
r.register_f<int (A::*)(void)>( "f", &A::f);
Другие вопросы по тегам