【问题标题】:Why can't I deduce one of the class template arguments?为什么我不能推断出类模板参数之一?
【发布时间】:2021-01-22 08:07:02
【问题描述】:

我这里有一些代码

template<typename T, std::size_t size, typename funcType>
struct foo
{
public:

    foo(const funcType& func) : m_func(func) {}
    ~foo() {}
    
    void m_call() { m_func(); }

private:
    const funcType& m_func;

    T x[size];
};

void printString() { std::cout << "some string\n"; }

我可以创建一个对象

foo<int, 3, void(*)()> someObject(printString);

foo<int, 3, decltype(printString)> someObject(printString);

但是当我尝试这样做时:

foo<int, 3> someObject(printString);

我在 g++ 10.2 上收到此错误

error: wrong number of template arguments (2, should be 3)
 foo<int, 3> someObject(printString);
           ^
note: provided for 'template<class T, long unsigned int size, class funcType> struct foo'
 struct foo
       

为什么我不能这样做?编译器不知道printString是什么类型吗?

如果我将foo 更改为

template<typename funcType>
struct foo
{
public:

    foo(const funcType& func) : m_func(func) {}
    ~foo() {}
    
    void m_call() { m_func(); }

private:
    const funcType& m_func;
};

我可以正常创建

foo someObject(printString);

我错过了什么吗?

【问题讨论】:

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


    【解决方案1】:

    使用模板函数创建对象并从函数调用中扣除缺少的模板参数。像这样。

    template<typename T, std::size_t Size, typename FunctionT>
    foo<T, Size, FunctionT> create_foo(const FunctionT &func) {
        return foo<T, Size, FunctionT>(func);
    } 
    
    auto foo_obj = create_foo<int, 3>(printString);
    

    【讨论】:

      【解决方案2】:

      根据cppreference

      类模板参数推导仅在没有模板时执行 参数列表存在。如果指定了模板参数列表, 不进行扣除。

      您上次的实验证实了这一点。要推导出funcType,您还需要在构造函数中提供其他模板类型以不提供任何模板参数列表。

      您可以将其他模板与构造函数绑定,例如使用此构造:

      #include <iostream>
      
      template<typename T, std::size_t size, typename funcType>
      struct foo
      {
      public:
          foo(T (&arr)[size], const funcType& func) : m_func(func) {}
          ~foo() {}
      
          void m_call() { m_func(); }
      
      private:
          const funcType& m_func;
          T x[size]{};
      };
      
      void printString() { std::cout << "some string\n"; }
      
      
      void test() {
          foo someObject("test", printString);
      
      }
      

      godbolt

      【讨论】:

      • 这并不能真正回答问题。 CTAD 要求推导出所有模板参数,这对于类的前 2 个参数是不可能的。
      • 嗯,问题是“为什么我不能推断出类模板参数之一?”,答案是你不能,因为你提供了部分信息,要么全部手动提供,要么不提供甚至开始演绎。我同意这会失败,因为构造函数只为最后一个模板参数创建指南。
      • 啊,我明白了。你是对的,这确实解决了这个问题。我看错了,因为你没有展示替代方案,但这很好。
      • 值得一提的是为什么存在这个限制,这是向后兼容带有默认模板参数的类模板。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-26
      • 1970-01-01
      • 2015-09-23
      • 2018-12-09
      相关资源
      最近更新 更多