为什么 "this" 在编译时在 consteval 构造函数中未知?
Why isn't "this" known at compile time in a consteval constructor?
我正在编写一个 class 来包装与设备一起工作的基于 C 的库的一部分,其中每个设备都配置有回调函数指针来处理数据。将为每个设备创建一个 MyClass
实例。见下文:
struct DeviceConfig {
void (*callback)(char *data);
};
class MyClass {
private:
DeviceConfig config;
public:
void myCallback(char *data);
MyClass() {
// Would like to set config.callback so that a call to it will result in a call of this->myCallback(data).
}
};
由于无法将捕获的 lambda 转换为函数指针,我尝试了以下解决方法:
template<MyClass *MC>
auto binder() {
return [](char *data) { MC->myCallback(data); };
}
MyClass::MyClass() {
config.callback = binder<this>();
}
但是,编译器(最新的 GCC)不喜欢在构造函数中使用 binder
,因为 this
在编译时不一定是已知的,尽管我知道MyClass
只会在编译时声明。
C++20 引入了 consteval
函数(和构造函数),其中 "must produce a compile-time constant."。但是,将 consteval
添加到构造函数 and/or binder
不会影响编译器的输出。 constexpr
也没有改变。
如果一个对象可以在编译时初始化,为什么不能在编译时也知道对象的 this
?以上是否可以通过其他方式实现?
构造函数是函数,就像其他函数一样。与其他函数相比,它们的特权很少,其参数的常量表达式行为也不在其中。
this
本质上是所有非静态成员函数的参数。参数为 never constant expressions。因此,this
不能用在需要常量表达式的上下文中。如何创建 class 实例并不重要。你怎么称呼它并不重要。 constexpr/consteval
函数的参数永远不是常量表达式,包括 this
.
接受的答案确实解释了为什么 this
不能在构造函数中使用;但是,我还询问是否有解决方法来实现我想要的。我找到了一个解决方法,并在另一个 Whosebug post .
中分享了该工作
为了节省点击次数,这是我的代码的最后一次迭代:
struct DeviceConfig {
void (*callback)(const char *);
};
template<auto& v, auto f>
constexpr auto member_callback = [](auto... args) { (v.*f)(args...); };
class MyClass {
private:
DeviceConfig config;
public:
consteval MyClass(const DeviceConfig& cfg = {}) :
config(cfg) {}
template<MyClass& MC>
constexpr static MyClass& init() {
MC.config.callback = member_callback<MC, &MyClass::myCallback>;
return MC;
}
void myCallback(const char *data);
};
int main()
{
constinit static MyClass mc = (mc = MyClass(), MyClass::init<mc>());
}
我正在编写一个 class 来包装与设备一起工作的基于 C 的库的一部分,其中每个设备都配置有回调函数指针来处理数据。将为每个设备创建一个 MyClass
实例。见下文:
struct DeviceConfig {
void (*callback)(char *data);
};
class MyClass {
private:
DeviceConfig config;
public:
void myCallback(char *data);
MyClass() {
// Would like to set config.callback so that a call to it will result in a call of this->myCallback(data).
}
};
由于无法将捕获的 lambda 转换为函数指针,我尝试了以下解决方法:
template<MyClass *MC>
auto binder() {
return [](char *data) { MC->myCallback(data); };
}
MyClass::MyClass() {
config.callback = binder<this>();
}
但是,编译器(最新的 GCC)不喜欢在构造函数中使用 binder
,因为 this
在编译时不一定是已知的,尽管我知道MyClass
只会在编译时声明。
C++20 引入了 consteval
函数(和构造函数),其中 "must produce a compile-time constant."。但是,将 consteval
添加到构造函数 and/or binder
不会影响编译器的输出。 constexpr
也没有改变。
如果一个对象可以在编译时初始化,为什么不能在编译时也知道对象的 this
?以上是否可以通过其他方式实现?
构造函数是函数,就像其他函数一样。与其他函数相比,它们的特权很少,其参数的常量表达式行为也不在其中。
this
本质上是所有非静态成员函数的参数。参数为 never constant expressions。因此,this
不能用在需要常量表达式的上下文中。如何创建 class 实例并不重要。你怎么称呼它并不重要。 constexpr/consteval
函数的参数永远不是常量表达式,包括 this
.
接受的答案确实解释了为什么 this
不能在构造函数中使用;但是,我还询问是否有解决方法来实现我想要的。我找到了一个解决方法,并在另一个 Whosebug post
为了节省点击次数,这是我的代码的最后一次迭代:
struct DeviceConfig {
void (*callback)(const char *);
};
template<auto& v, auto f>
constexpr auto member_callback = [](auto... args) { (v.*f)(args...); };
class MyClass {
private:
DeviceConfig config;
public:
consteval MyClass(const DeviceConfig& cfg = {}) :
config(cfg) {}
template<MyClass& MC>
constexpr static MyClass& init() {
MC.config.callback = member_callback<MC, &MyClass::myCallback>;
return MC;
}
void myCallback(const char *data);
};
int main()
{
constinit static MyClass mc = (mc = MyClass(), MyClass::init<mc>());
}