以下代码无法在g ++ 7.2.0中编译
template <class Internal>
class Request {
int content = 0;
public:
friend void setContent(int i, void *voidptr) {
Request<Internal> *ptr = (Request<int>*)voidptr;
ptr->content = i;
}
int getContent() {return content;}
};
int main() {
Request<int> req;
setContent(4, &req);
return req.getContent();
}
Run Code Online (Sandbox Code Playgroud)
有错误
test.cpp: In instantiation of ‘void setContent(int, void*)’:
test.cpp:14:23: required from here
test.cpp:7:14: error: use of local variable with automatic storage from containing function
ptr->content = i;
~~~~~^~~~~~~
test.cpp:6:28: note: ‘Request<Internal>* ptr’ declared here
Request<Internal> *ptr = (Request<int>*)voidptr;
Run Code Online (Sandbox Code Playgroud)
我不明白这有什么问题(除了愚蠢的例子).Clang 4.0.1似乎接受了它,我很确定它是在g ++ 5.4下编译的.另外:如果我删除所有模板,这个编译好了.
是编译器中的这个错误还是我违反了一些我不知道的规则?
编辑它似乎从gcc 7.x开始停止工作https://godbolt.org/g/D6gqcF
我不知道 GCC 是否合理地拒绝这种结构,但似乎完全缺乏 的Request<Internal>类型使它感到困惑。您可以引用的唯一原因是注入的类名,它来自定义的范围。setContentRequest<Internal>
template <class Internal>
class Request {
int content = 0;
public:
friend void setContent(int i, void *voidptr); // shouldn't make a difference
int getContent() {return content;}
};
void setContent(int i, void * voidptr)
{
// Where does Internal come from?
Request<Internal> *ptr = (Request<Internal>*)voidptr;
ptr->content = i;
}
Run Code Online (Sandbox Code Playgroud)
我认为您不需要这里的模板,因为如果您使用第二种类型实例化它,则会违反单一定义规则。
class RequestBase {
int content = 0;
public:
virtual ~RequestBase() = default;
friend void setContent(int i, RequestBase * ptr) {
ptr->content = i;
}
int getContent() {return content;}
};
Run Code Online (Sandbox Code Playgroud)
如果您的类中有其他成员使用Internal,您可以使用模板子类添加它们
template <class Internal>
class Request : public RequestBase {
// members involving Internal
};
Run Code Online (Sandbox Code Playgroud)
另一种选择是您Internal在参数中使用setContent
template <class Internal>
class Request {
Internal content = 0;
public:
friend void setContent(Internal i, void *voidptr){
Request<Internal> *ptr = (Request<Internal>*)voidptr;
ptr->content = i;
}
Internal getContent() {return content;}
};
Run Code Online (Sandbox Code Playgroud)
或者
template <class Internal>
class Request {
int content = 0;
public:
friend void setContent(int i, Request<Internal> *ptr) {
ptr->content = i;
}
int getContent() {return content;}
};
Run Code Online (Sandbox Code Playgroud)
请注意,您仍然可以绑定void setContent(int, Request<Internal> *)到void (*)(int, void *)函数指针等