使用模板函数传递模板参数的错误

时间:2018-05-03 18:12:19

标签: c++ function templates arguments member

我在使用模板成员函数和模板变量时遇到了问题。目标是为接口创建一个模板,该模板可以继承并链接到在运行时初始化的一个或多个服务。该接口还将数据传递给这些专用服务(例如MyService)。有关更简单的示例,请使用以下代码:

C2672: 'Interface::AttachedService': no matching overloaded function found
C2783:  'T Interface::AttachedService(void)': could not deduce template argument for 'T'
C2228:  left of '.setA' must have class/struct/union
C3245:  'Interface::m_AttachedService': use of a variable template requires template argument list

我收到以下错误:

>>> t1 = tf.Variable(tf.ones([2,3,4],tf.int32))
>>> t2 = tf.Variable(tf.zeros([2,3,4],tf.int32))
>>> t1
<tf.Variable 'Variable_4:0' shape=(2, 3, 4) dtype=int32_ref>
>>> t2
<tf.Variable 'Variable_5:0' shape=(2, 3, 4) dtype=int32_ref>

理解正确使用模板的任何帮助都将受到赞赏!

1 个答案:

答案 0 :(得分:0)

让我们从构建和运行的最小程序开始,而不做任何有用的事情。

#include <string>

class Interface
{
};

class Service
{
   protected:
      Service() {}
      ~Service() {}
      virtual void init() = 0;
};

class MyService : public Service, public Interface
{
   private:
      int A;
      std::string B;
   protected:
      Interface x;
   public:
      MyService() {}
      ~MyService() {}
      void init() {}
      void setA(int a) { A = a; }
      void setB(std::string b) { B = b; }
};

int main()
{
   MyService myserv;
   myserv.init();
}

您会注意到,您发布的代码几乎没有任何变化可以达到该基线。

  1. Interface是空的。
  2. Service的成员函数位于public部分。 Service的默认构造函数和析构函数具有空实现。
  3. MyService的默认构造函数和析构函数位于类的public部分,它们具有空实现。
  4. MyService::init()有一个空实现。
  5. 现在我们可以开始添加更多代码了。

    我将MyService::init()更改为:

      void init() { x.init(this); }
    

    没有其他更改,我收到以下编译器错误。

    socc.cc: In member function ‘virtual void MyService::init()’:
    socc.cc:25:23: error: ‘class Interface’ has no member named ‘init’
           void init() { x.init(this);}
    

    现在,Interface需要使用init函数进行更新。

    我添加了一个虚拟实现来推动这个过程。

    class Interface
    {
       public:
          template <class T> bool init(T *_Service) { return true; }
    };
    

    是时候向Interface::init()添加有用的内容了。将其更改为

    template <class T> bool init(T *_Service)
    {
       AttachService(*_Service); 
       return true; 
    }
    

    产生以下编译器错误,这并不奇怪。

    socc.cc: In instantiation of ‘bool Interface::init(T*) [with T = MyService]’:
    socc.cc:31:32:   required from here
    socc.cc:8:23: error: ‘AttachService’ was not declared in this scope
              AttachService(*_Service);
              ~~~~~~~~~~~~~^~~~~~~~~~~
    

    添加AttachService的时间。将Interface更改为(与您拥有的内容相匹配)

    class Interface
    {
       public:
          template <class T> bool init(T *_Service)
          {
             AttachService(*_Service); 
             return true; 
          }
    
          template <typename T> void AttachService(T _Service)
          {
             m_AttachedService<T> = *_Service;
          }
    
       protected:
          template<typename T> static T m_AttachedService;
    };
    

    产生以下编译器错误。

    socc.cc: In instantiation of ‘void Interface::AttachService(T) [with T = MyService]’:
    socc.cc:8:10:   required from ‘bool Interface::init(T*) [with T = MyService]’
    socc.cc:39:32:   required from here
    socc.cc:14:33: error: no match for ‘operator*’ (operand type is ‘MyService’)
              m_AttachedService<T> = *_Service;
                                     ^~~~~~~~~
    

    这是有道理的。在AttachServie中,_Service不是指针。

    Inteface::AttachService更改为:

      template <typename T> void AttachService(T _Service)
      {
         m_AttachedService<T> = _Service;
      }
    

    使编译器错误消失,但存在链接器错误。

    :socc.cc:(.rdata$.refptr._ZN9Interface17m_AttachedServiceI9MyServiceEE[.refptr._ZN9Interface17m_AttachedServiceI9MyServiceEE]+0x0): undefined reference to `Interface::m_AttachedService<MyService>'
    collect2: error: ld returned 1 exit status
    

    这是有道理的,因为我们还没有定义static成员变量。

    添加以下行

    template<typename T> T Interface::m_AttachedService;
    
    在定义Interface后,

    负责链接器错误。

    以下是成功构建并运行的完整程序的下一个版本,即使它仍然没有做任何有用的事情。

    #include <string>
    
    class Interface
    {
       public:
          template <class T> bool init(T *_Service)
          {
             AttachService(*_Service); 
             return true; 
          }
    
          template <typename T> void AttachService(T _Service)
          {
             m_AttachedService<T> = _Service;
          }
    
       protected:
          template<typename T> static T m_AttachedService;
    };
    
    template<typename T> T Interface::m_AttachedService;
    
    class Service
    {
       protected:
          Service() {}
          ~Service() {}
          virtual void init() = 0;
    };
    
    class MyService : public Service, public Interface
    {
       private:
          int A;
          std::string B;
       protected:
          Interface x;
       public:
          MyService() {}
          ~MyService() {}
          void init() { x.init(this); }
          void setA(int a) { A = a; }
          void setB(std::string b) { B = b; }
    };
    
    int main()
    {
       MyService myserv;
       myserv.init();
    }
    

    是时候将AttachedService版本添加到Interface

    template <typename T> T AttachedService() { return m_AttachedService; }
    

    这会产生以下编译器错误。

    socc.cc: In member function ‘T Interface::AttachedService()’:
    socc.cc:17:73: error: missing template arguments before ‘;’ token
         template <typename T> T AttachedService() { return m_AttachedService; }
    

    这是有道理的,因为m_AttachedService不是成员变量,而是成员变量模板。

    将其更改为

    template <typename T> T AttachedService() { return m_AttachedService<T>; }
    

    删除该错误。

    现在是Interface中的最后一部分。您发布的嵌套类InterfaceListener听起来不错。

      class InterfaceListener
      {
         void Received()
         {
            int a = 1;
            std::string b = "hello";
            AttachedService().setA(a);
            m_AttachedService.setB(b);
         };
      };
    

    该课程中的问题:

    1. AttachedService()不正确,因为它是成员函数模板。您必须提供模板参数才能使用它。
    2. 此外,AttachedService()不是static成员函数。您需要Interface的实例才能拨打电话。
    3. m_AttachedService不是成员变量。它是一个成员变量模板。您必须提供模板参数才能使用它。
    4. 仅当模板参数为setA()时,函数setB()MyService才有效。在该函数中使用特定于类型的代码是没有意义的。
    5. 我会让你思考你打算如何使用InterfaceListener并适当地定义它的功能。在此之前,以下程序为我构建并运行。

      #include <string>
      
      class Interface
      {
         public:
            template <class T> bool init(T *_Service)
            {
               AttachService(*_Service); 
               return true; 
            }
      
            template <typename T> void AttachService(T _Service)
            {
               m_AttachedService<T> = _Service;
            }
      
            template <typename T> T AttachedService() { return m_AttachedService<T>; }
      
         protected:
            template<typename T> static T m_AttachedService;
      
      };
      
      template<typename T> T Interface::m_AttachedService;
      
      class Service
      {
         protected:
            Service() {}
            ~Service() {}
            virtual void init() = 0;
      };
      
      class MyService : public Service, public Interface
      {
         private:
            int A;
            std::string B;
         protected:
            Interface x;
         public:
            MyService() {}
            ~MyService() {}
            void init() { x.init(this); }
            void setA(int a) { A = a; }
            void setB(std::string b) { B = b; }
      };
      
      int main()
      {
         MyService myserv;
         myserv.init();
      }