我在使用模板成员函数和模板变量时遇到了问题。目标是为接口创建一个模板,该模板可以继承并链接到在运行时初始化的一个或多个服务。该接口还将数据传递给这些专用服务(例如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>
理解正确使用模板的任何帮助都将受到赞赏!
答案 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();
}
您会注意到,您发布的代码几乎没有任何变化可以达到该基线。
Interface
是空的。Service
的成员函数位于public
部分。 Service
的默认构造函数和析构函数具有空实现。MyService
的默认构造函数和析构函数位于类的public
部分,它们具有空实现。MyService::init()
有一个空实现。现在我们可以开始添加更多代码了。
我将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);
};
};
该课程中的问题:
AttachedService()
不正确,因为它是成员函数模板。您必须提供模板参数才能使用它。AttachedService()
不是static
成员函数。您需要Interface
的实例才能拨打电话。m_AttachedService
不是成员变量。它是一个成员变量模板。您必须提供模板参数才能使用它。setA()
时,函数setB()
和MyService
才有效。在该函数中使用特定于类型的代码是没有意义的。我会让你思考你打算如何使用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();
}