C++ “伪造”;使用包含函数“的自动存储的局部变量”;用c++;模板?

C++ “伪造”;使用包含函数“的自动存储的局部变量”;用c++;模板?,c++,templates,gcc,C++,Templates,Gcc,以下代码不在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; }

以下代码不在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();
}
模板
类请求{
int-content=0;
公众:
朋友void setContent(int i,void*voidptr){
请求*ptr=(请求*)无效ptr;
ptr->content=i;
}
int getContent(){return content;}
};
int main(){
请求请求;
设置内容(4和要求);
返回req.getContent();
}
错误地

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;
test.cpp:在“void setContent(int,void*)”的实例化中:
测试。cpp:14:23:从这里开始需要
test.cpp:7:14:错误:使用包含函数自动存储的局部变量
ptr->content=i;
~~~~~^~~~~~~
test.cpp:6:28:注意:此处声明了“请求*ptr”
请求*ptr=(请求*)无效ptr;
我不明白这有什么不对(除了作为一个愚蠢的例子)。Clang4.0.1似乎接受了它,我很确定它是在g++5.4下编译的 另外:如果我删除了所有模板,则编译正常

这是编译器中的错误还是我违反了一些我不知道的规则

编辑
似乎它从gcc 7.x开始就停止工作了,我不知道gcc是否在合理地阻止这种构造,但似乎在
setContent
类型中完全缺少
请求
使它感到困惑。您可以引用
请求的唯一原因是注入的类名,它来自定义的范围

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;
}
如果您的类中有其他成员使用
Internal
,则可以使用模板子类添加它们

template <class Internal>
class Request : public RequestBase {
    // members involving Internal
};

模板
类请求{
int-content=0;
公众:
好友无效设置内容(int i,请求*ptr){
ptr->content=i;
}
int getContent(){return content;}
};

请注意,您仍然可以将
void setContent(int,Request*)
绑定到
void(*)(int,void*)
函数指针等

这看起来确实很棘手。让我们再看看这句话:

Request*ptr=(Request*)voidptr

这是两种不同的类型。如何在一种类型和另一种类型之间转换?好的,最明显的方法是从派生到基的转换

现在,您可以说,
Request
不是派生类。如果我们看看整个计划,那是真的。但是在模板编译的第一阶段,编译器还没有看到任何模板专门化。仍然可能有一个专门化的
请求
,以后可能会引入一个基类(!)


<>我必须抓住适当的C++标准来检查这个区域中的一些细微的变化,但是从工程的角度来看,当这些代码在面对小的编译器更改时证明是脆弱的时,就不足为奇了。p> 我可以确认它在g++6.3.0下编译时没有错误。顺便说一下:如果您打算用不同的代码实例化此模板,您可能希望将
void*
转换为
Request*
,而不是
Request*
type@Caleth是的,但不会改变任何事情。这是准备好的示例中的错误,不是实际的code@Caleth我想您已经注意到了这个问题,因为在
朋友void setContent(int I,void*voidptr)
的声明中,将
int
替换为
Internal
。虽然这是一种相当隐晦的拼写方式,但我已经把你的例子分了一小部分,发现了一些与上面所说的相同的东西。在这一点上,你可以看到区别:引用OP:“我不明白这有什么错(除了是一个愚蠢的例子)”,所以我不认为问题的答案是找到一个替代设计,因为问题的核心是gcc如何处理这个特定的例子。虽然很明显,编写实际代码是一个更好的主意,我不认为它回答了真正的问题,是否允许编译器拒绝代码。在中找不到任何东西表明代码格式不正确-只要模板最多实例化一次。但是你指出这是一种非常糟糕的风格是对的。好吧,我目前的理论是代码很糟糕(我以前就知道),gcc因为7.x被它的错误弄糊涂了。我非常确定,在任何范围内实际上都没有多个setContent定义,因为如果有以前的版本,也不会编译。我将不得不考虑如何应用其中一个建议。遗憾的是,实际的代码更像friend void setContent(inti,http_解析器){Request*ptr=(Request)parser->data;…其中http_解析器没有模板化,数据是void*,因此需要进行多次更改
template <class Internal>
class Request : public RequestBase {
    // members involving Internal
};
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;}
};
template <class Internal>
class Request {
    int content = 0;
public:
    friend void setContent(int i, Request<Internal> *ptr) {
        ptr->content = i;
    }
    int getContent() {return content;}
};