【问题标题】:Type deduction with template, method pointer and strings使用模板、方法指针和字符串进行类型推导
【发布时间】:2017-04-23 15:56:24
【问题描述】:

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

让我们看下面的代码:

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

但我不是很喜欢它

【问题讨论】:

  • 你有多不喜欢testTemplateFct(&amp;testClass, &amp;TestClass::testMethodStringArg, +"a string...");
  • 更好。但是,它绕过了我的问题,但并没有解决它

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


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    注意"a string..." 是一个类型为const char[12] 的数组。对于函数模板testTemplateFct,参数arg1被声明为reference,即const Arg1T &amp;,则template argument deductionArg1T不会发生array-to-pointer衰减推导为char[12],与第二个参数推导出的Arg1T类型不匹配,即const char*,所以推导失败。

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

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

    【讨论】:

      【解决方案3】:

      您有两个基本选择。

      第一个是将调用更改为:

      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 * 在普通函数调用中;但是这种衰减不会作为模板推导的一部分发生;因此问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-06-22
        • 2014-09-22
        • 2018-06-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-16
        • 1970-01-01
        相关资源
        最近更新 更多