Вывод типа с шаблоном, указателем метода и строками

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

Давайте возьмем следующий код:

template <class ClassT, typename Arg1T>
inline void testTemplateFct(ClassT * clazz,
                void (ClassT::*fctPtr)(Arg1T),
                const Arg1T & arg1)
{

}


class TestClass
{

public:
  void testMethodIntArg(int arg)
  {}

  void testMethodDoubleArg(double arg)
  {}

  void testMethodStringArg(const char * arg);

};



int main()
{
  TestClass testClass;

  testTemplateFct(&testClass,
          &TestClass::testMethodIntArg,
          10);

  testTemplateFct(&testClass,
          &TestClass::testMethodDoubleArg,
          10.0);

  /// BEGINNING OF MY PROBLEM
  testTemplateFct(&testClass,
          &TestClass::testMethodStringArg,
          "a string...");
  /// END OF MY PROBLEM

  return 0;
}

Если я скомпилирую его с помощью g++, я получу следующее сообщение об ошибке:

$ g++ ArgumentDeduction.cpp -o ArgumentDeduction
ArgumentDeduction.cpp: In function ‘int main()’:
ArgumentDeduction.cpp:42:18: error: no matching function for call to ‘testTemplateFct(TestClass*, void (TestClass::*)(const char*), const char [12])’
     "a string...");
                  ^
ArgumentDeduction.cpp:4:13: note: candidate: template<class ClassT, class Arg1T> void testTemplateFct(ClassT*, void (ClassT::*)(Arg1T), const Arg1T&)
 inline void testTemplateFct(ClassT * clazz,
             ^~~~~~~~~~~~~~~
ArgumentDeduction.cpp:4:13: note:   template argument deduction/substitution failed:
ArgumentDeduction.cpp:42:18: note:   deduced conflicting types for parameter ‘const Arg1T’ (‘const char*’ and ‘char [12]’)
     "a string...");

Если я удалю ссылку на третий аргумент метода testTemplateFct проблема исчезает (ОДНАКО АБСОЛЮТНО НУЖНА ССЫЛКА, ЧТОБЫ ИЗБЕЖАТЬ КОПИРОВАНИЯ)

template <class ClassT, typename Arg1T>
inline void testTemplateFct(ClassT * clazz,
                void (ClassT::*fctPtr)(Arg1T),
                const Arg1T  arg1)
{}

Я более или менее понимаю сообщение об ошибке, но я не понимаю, почему существует неопределенность между const char* а также char [12], Я не понимаю, почему проблема исчезает, когда я удаляю ссылку.

Наконец, я был бы очень признателен за любую помощь, чтобы исправить этот код, сохраняя при этом ссылку

PS: я знаю, что могу "форсировать" вывод типа, выполнив:

testTemplateFct(&testClass,
                &TestClass::testMethodStringArg,
                (const char *) "a string...");

но мне это не очень нравится

3 ответа

Я не понимаю, почему существует неопределенность между const char* а также char [12],

Обратите внимание, что "a string..." это массив с типом const char[12], Для шаблона функции testTemplateFctпараметр arg1 объявлен как ссылка, т.е. const Arg1T &то затухание массива в указатель не произойдет при выводе аргумента шаблона и Arg1T выводится как char[12], который не соответствует выведенному типу Arg1T из второго аргумента, т.е. const char*Таким образом, удержание не удалось.

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

Когда параметр объявляется как переход от значения к массиву, применяется затухание; тогда как выведенный тип Arg1T от 2-го и 3-го аргумента будет const char* и все работает нормально.

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

template <class ClassT, typename Arg1T, typename GivenT>
inline void testTemplateFct(ClassT * clazz,
                void (ClassT::*fctPtr)(Arg1T),
                GivenT &&arg1)
{
    //example use
    (clazz->*fctPtr)(std::forward<GivenT>(arg1));
}

У вас есть два основных варианта.

Первый - изменить ваш вызов на:

testTemplateFct(&testClass,
          &TestClass::testMethodStringArg,
          (const char *)"a string...");

Второй вариант - добавить перегрузку:

template <class ClassT, size_t n>
inline void testTemplateFct(ClassT * clazz,
                void (ClassT::*fctPtr)(const char *),
                const char (&arg1)[n])
{
    testTemplateFct<ClassT, const char *>(clazz, fctPtr, arg1);
}

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

Буквенная строка символов на самом деле const char[n]и не const char *, const char массив распадается наconst char * в обычном вызове функции; но этот распад не происходит как часть вычитания шаблона; отсюда и проблема.

Другие вопросы по тегам