使用模板,方法指针和字符串键入演绎

时间:2017-04-23 15:56:25

标签: c++ templates type-deduction template-deduction argument-deduction

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

我们来看下面的代码:

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 个答案:

答案 0 :(得分:2)

  

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

请注意,"a string..."是一个类型为const char[12]的数组。对于函数模板testTemplateFct,参数arg1被声明为引用,即const Arg1T &,则Arg1T中不会发生数组到指针的衰减{3}}和char[12]推断为Arg1T,与第二个参数的const char*的推导类型不匹配,即Arg1T,因此扣除失败。< / p>

  

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

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

答案 1 :(得分:2)

您的模板要求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)); } 的出现次数推导为相同类型。我相信这不是你想要的。相反,应该独立推断出类型:

{{1}}

答案 2 :(得分:1)

您有两个基本选项。

第一个是将您的调用更改为:

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 *。普通函数调用中的The const char array decays to a const char *;但这种衰变不会作为模板扣除的一部分发生;因此问题。