Вызывающая метод C ++ шаблон-функция не может вызывать перегруженные методы - PullRequest
2 голосов
/ 19 октября 2010

Если у вас есть эта общая функция:

template<class type, class ret, class atype1, class atype2, class atype3>
ret call3(type *pClass, ret(type::* funcptr)(atype1, atype2, atype3), atype1 arg, atype2 arg2, atype3 arg3)
{
    //do some stuff here
    return (pClass->*funcptr)(arg, arg2, arg3);
}

и вы делаете это:

class MyClass
{
  public: 
    void test(int, int, int){};
    void test(int, int){};
    void test(int, int, const char *){};  //comment this line, and it works fine.
};

...

    MyClass *a = new MyClass();
    call3(a, &MyClass::test, 1, 2, 3);

г ++ скажет:

no matching function for call to `call3(MyClass*&, <unknown type>, int, int, int)'

Есть ли способ исправить это? (Мой код, вероятно, очень плохой, так как я не очень хорош в C ++.)

Ответы [ 5 ]

3 голосов
/ 19 октября 2010

Вы можете явно указать, какой шаблон использовать.

call3<MyClass, void, int, int, int>( a, &MyClass::test, 1, 2, 3 );

Если вы измените порядок параметров вашего шаблона, вы можете получить MyClass и void, выведенные из аргумента, поэтому вызов при необходимости перегрузки будет выглядеть следующим образом:

call3<int,int,int>( a, &MyClass::test, 1, 2, 3 )

Обратите внимание, что когда вам на самом деле не нужно явное разрешение перегрузки, оно все равно может быть

call3( a, &MyClass::otherfunction, 1,2,3 );
3 голосов
/ 19 октября 2010

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

call3(a, static_cast<void (MyClass::*)(int, int, int)>(&MyClass::test), 1, 2, 3);

Это не совсем так чисто.Вероятно, было бы лучше дать функциям разные имена.

2 голосов
/ 19 октября 2010

Причина в том, что у компилятора есть две перегрузки на выбор, каждая из которых принимает три параметра. Обратите внимание, что в процессе вывода аргументов компилятор выводит участвующие параметры шаблона из аргументов вызова функции, независимо просматривая пару параметр / аргумент.

Вывод аргумента успешен только тогда, когда параметры шаблона определены однозначно с учетом каждой пары параметр / аргумент. Это означает, что, глядя на вашу вторую пару параметр / аргумент, он полагается (и не может) полагаться на тот факт, что atype1, atype2 и atype3 имеют тип int, даже если вы изменили параметры шаблона как

template<class type, class ret, class atype1, class atype2, class atype3> 
ret call3(type *pClass, atype1 arg, atype2 arg2, atype3 arg3, ret(type::* funcptr)(atype1, atype2, atype3)) 
{ 
    //do some stuff here 
    return (pClass->*funcptr)(arg, arg2, arg3); 
} 

Вот цитата из стандарта, которая поддерживает это:

Не выведенные контексты:

- The nested-name-спецификатор типа, который был указан с помощью квалифицированного идентификатора.

- Нетипичный аргумент шаблона или связанный массив, в котором подвыражение ссылается на параметр шаблона.

- А параметр шаблона, используемый в тип параметра параметра функции который имеет аргумент по умолчанию, который используется в вызове, для которого вывод аргумента делается.

- A параметр функции, для которого аргумент удержание не может быть сделано, потому что аргумент связанной функции является функция или набор перегруженных функции (13.4) и один или несколько применяется следующее:

- более одного функция соответствует функции тип параметра (в результате чего двусмысленный вывод) или

- нет функции соответствует типу параметра функции, или

- набор функций поставляется в виде аргумент содержит один или несколько шаблоны функций.

Теперь для решения,

Я думаю, что единственным решением является то, что вам придется явно указывать параметры шаблона, а не полагаться на вывод аргумента шаблона. Небольшая перестановка параметров шаблона поможет

template<class atype1, class atype2, class atype3, class type, class ret> 
ret call3(type *pClass, ret(type::* funcptr)(atype1, atype2, atype3), atype1 arg, atype2 arg2, atype3 arg3) 
{ 
    //do some stuff here 
    return (pClass->*funcptr)(arg, arg2, arg3); 
} 

int main(){
    MyClass *a = new MyClass(); 
    call3<int, int, int>(a, &MyClass::test, 1, 2, 3); 
}
0 голосов
/ 19 октября 2010

Я думаю, что проблема здесь в том, что компилятор не может определить, на какую test функцию вы ссылаетесь.

Если предположить, что у вас есть следующие методы

void test(int, int, int);
void test(int, int, const char *); 

Теперь, если вы позвоните test, как это

test(1, 2, 3);

3 может быть неявно преобразовано в const char *. Таким образом, компилятор не сможет разрешить между двумя перегрузками функции test и, следовательно, ошибкой компиляции.

Решение, данное JoshD, должно решить вашу проблему

0 голосов
/ 19 октября 2010

Компилятор не может определить тип возвращаемого параметра.Вам нужно будет явно указать параметры шаблона call3.

...