Вывод типа шаблона для указателя на функцию-член - PullRequest
3 голосов
/ 01 апреля 2011

У меня очень похожая проблема с проблемой, предложенной Морфеусом в следующем вопросе:

Перегружен указатель на функцию-член на шаблон

Решение, предложенное Ричардом Корденомтребует от пользователя явного указания типа параметра функции, чтобы различать его среди перегрузок.Однако это решение, по-видимому, не работает с перегрузками с различным числом аргументов того же типа .

. Рассмотрим этот пример (полученный из исходного вопроса):

template <typename T>
class A
{
public:
  template<class Arg1>
  void connect(void (T::*f)(Arg1)) 
  {
    //Do some stuff
  }

  template<class Arg1, class Arg2>
  void connect(void (T::*f)(Arg1,Arg2)) 
  {
    //Do some stuff
  }

  void connect(void (T::*f)()) 
  {
    //Do some stuff
  }
};

class GApp
{
public:
    void foo() {}
    void foo(double d) {}
    void foo(double d1, double d2) {}
};


int main ()
{
  A<GApp> a;
  a.connect (&GApp::foo);                // foo () - OK
  a.connect<double> (&GApp::foo);        // foo (double) - FAIL
  a.connect<double,double> (&GApp::foo); // foo (double,double) - OK
}

GNU G ++ 3.4.5 и MSVC 2008 не компилируют приведенный выше код, оба представляют похожие сообщения об ошибках:

test.cpp: In function `int main()':
test.cpp:36: error: call of overloaded `connect(<unknown type>)' is ambiguous
test.cpp:7: note: candidates are: void A<T>::connect(void (T::*)(Arg1)) [with Arg1 = double, T = GApp]
test3.cpp:13: note:               void A<T>::connect(void (T::*)(Arg1, Arg2)) [with Arg1 = double, Arg2 = double, T = GApp]

Мне известны некоторые обходные пути, которые могут сделатьон компилируется, как присвоение указателя переменной того же типа (например, void (GApp::*tmp)(double) = &GApp::foo;), или использование более подробной формы при вызове функции соединения (например, connect((void (GApp::*)(double))(&GApp::foo));).

Однако я предпочитаюпервое решение и хотелось бы узнать почему не работает.

Заранее спасибо!

Ответы [ 2 ]

8 голосов
/ 01 апреля 2011

Для a.connect<double> (&GApp::foo) и foo(double), и foo(double, double) будут соответствовать перегрузке connect с одним и двумя параметрами шаблона соответственно (в случае версии с двумя параметрами, второй аргумент шаблона будет вывод, первый аргумент был предоставлен вами явно).

Если вы хотите избавиться от неоднозначных случаев, я рекомендую передать точный тип, чтобы не было никаких неожиданностей. Вместо этих перегрузок, почему бы не иметь одну перегрузку

template<typename MType, typename T>
void connect(MType T::*f) 
{
  //Do some stuff
}

a.connect<void()> (&GApp::foo);
a.connect<void(double)> (&GApp::foo);
a.connect<void(double, double)> (&GApp::foo);

Последний вызов connect также должен нормально работать в вашем коде. Затем вы можете разделить тип MType в connect с помощью отдельных шаблонов, чтобы получить параметры и типы возврата.

0 голосов
/ 01 апреля 2011

Проблема с исходным кодом заключается в том, что вы явно определяете неправильную часть.Когда вы указываете список параметров шаблона, даже если вы указываете один, компилятор попытается вывести второй, а затем снова перейдет к неоднозначности, потому что не знает, хотите ли вы использовать (double, double) илиdouble) Variation.

Вместо определения параметров шаблона, пусть компилятор выводит их, но явно указывает, какую из функций foo () вы хотите использовать:

int main()
{
    A<GApp> a;
    a.connect (&GApp::foo);                                     // foo () - OK
    a.connect( ( void (GApp::*)(double) )&GApp::foo);           // foo (double) - OK
    a.connect( ( void (GApp::*)(double, double) ) &GApp::foo);  // foo (double,double) - OK
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...