Вывод типа с шаблоном, указателем метода и строками
Я столкнулся с серьезной проблемой вывода типа шаблона, когда я использую указатель метода в аргументе функции шаблона.
Давайте возьмем следующий код:
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 *
в обычном вызове функции; но этот распад не происходит как часть вычитания шаблона; отсюда и проблема.