使用模板、方法指针和字符串键入推导

Type deduction with template, method pointer and strings

本文关键字:字符串 指针 方法      更新时间:2023-10-16

当我在模板函数的参数中使用方法指针时,我遇到了严重的模板类型推断问题。

让我们采用以下代码:

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...");

但我不太喜欢它

您的模板要求将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));
}

我不明白为什么const char*char [12]之间存在歧义.

请注意,"a string..."是类型为const char[12]的数组。对于函数模板testTemplateFct,参数arg1被声明为引用,即const Arg1T &,那么数组到指针衰减不会发生在模板参数推导中,Arg1T被推导为char[12],这与从第二个参数推导的Arg1T类型不匹配,即const char*,所以推论失败。

我不明白为什么当我删除引用时问题消失了。

当参数被声明为按值传递数组到指针衰减时;那么从第二个和第三个参数推导出的Arg1T类型都将const char*,一切正常。

您有两个基本选项。

第一个是将调用更改为:

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 *;但这种衰减不会作为模板演绎的一部分发生;因此问题来了。