伪造"使用包含函数的自动存储的局部变量"和c ++模板?

Mat*_*szL 9 c++ gcc templates

以下代码无法在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

Cal*_*eth 2

不知道 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 *)函数指针等

  • 虽然显然,编写实际代码是一个更好的主意,但我认为它并不能回答真正的问题,即是否允许编译器拒绝代码。 (3认同)