constexpr 可构造函数对象
Constexpr constructible function object
我有一个与 有点相似的问题,但对于更有限的情况,我认为应该可以通过某种方式实现:我想从多个 lambda 构建一个函数调用的静态 constexpr 数组,每个共享相同的签名。 static 和 constexpr 部分在这里很重要,因为我在嵌入式系统上,我想确保这些表最终出现在 Flash 中。
所以基本上我想做的是
#include<vector>
#include<functional>
#include<variant>
using params_t = std::vector<std::variant<int, float /*maybe others*/ >>;
struct command_t {
using callable_t = std::function<void(params_t)>;
const callable_t func;
//other members..
};
class AClass {
template<typename func_t>
constexpr static command_t::callable_t make_callable(func_t fun) {
return [fun](params_t params){/*construct a call to fun using params and template magic*/};
}
static void mycommand();
static void mycommand2(int i);
//The following fails:
///"error: in-class initialization of static data member 'const command_t AClass::commands [2]' of non-literal type"
static constexpr command_t commands[2] = {command_t{make_callable(mycommand)},
command_t{make_callable(mycommand2)}};
};
请注意,此处的类型擦除非常有限,因为 lambda 的签名仅因 fun
的捕获签名而异。函数调用显然不需要(也不可能)是 constexpr,只需要构造。
所以基本上我的问题是我能否以某种方式制作 commands
数组 static constexpr
,或者使用 std::function,
或 inplace_function 之类的东西,或者通过我自己的旋转在这种特定情况下类型擦除 lambda 的代码?
由于 mycommanN
具有不同的签名并且您需要捕获它们,所以我看不到有 constexpr 向量的方法。也许有人可以想出更好的设计。
我有一个解决方案:使用 std::tuple
。但我不太喜欢,因为使用 tuple
作为容器真的很麻烦。例如迭代它是……假设不是在公园散步。无论如何,这里是万一它确实有帮助:
using params_t = std::vector<std::variant<int, float /*maybe others*/>>;
// I needed to lift this out of AClass because of ... complicated reasons
// (short version: when both are AClass members
// the return type of `make_command` is not resolved in the init of `commands`
// because both are static, `commands` is not a template and `make_command` is a template
// tbh I don't know exactly what is happening. It's one of those dark corners of C++)
template <class RealFunc>
static constexpr auto make_command(RealFunc real_func) {
return [real_func](params_t params) { /*magic*/ };
}
struct AClass {
static void mycommand();
static void mycommand2(int i);
static constexpr std::tuple commands{make_command(mycommand),
make_command(mycommand2)};
};
// usage
auto test() {
constexpr auto command0 = std::get<0>(AClass::commands<>);
params_t params0 = {};
return command0(command0);
}
一般来说,这是不可能的,因为 lambda 的捕获可以变得任意大,因此,在某些时候我们需要一个堆分配,然后杀死 constexpr pre-C++20 的任何希望(我不也不认为 C++20 对这种情况有多大帮助)。
但是如果我没看错,你只想捕获一个函数指针,我们可以这样做:
#include <vector>
#include<variant>
using params_t = std::vector<std::variant<int, float /*maybe others*/ >>;
struct command_t {
using callable_t = void (*)(std::vector<params_t>);
const callable_t func;
//other members..
};
template<auto f>
void wrap(std::vector<params_t>){
// make this dependent of f, maybe use function_traits for fancy stuff
}
class AClass {
static void mycommand();
static void mycommand2(int i);
static constexpr command_t commands[2] = {wrap<mycommand>, wrap<mycommand2>};
};
int main() {
}
感谢xskxzr的宝贵建议
我有一个与
所以基本上我想做的是
#include<vector>
#include<functional>
#include<variant>
using params_t = std::vector<std::variant<int, float /*maybe others*/ >>;
struct command_t {
using callable_t = std::function<void(params_t)>;
const callable_t func;
//other members..
};
class AClass {
template<typename func_t>
constexpr static command_t::callable_t make_callable(func_t fun) {
return [fun](params_t params){/*construct a call to fun using params and template magic*/};
}
static void mycommand();
static void mycommand2(int i);
//The following fails:
///"error: in-class initialization of static data member 'const command_t AClass::commands [2]' of non-literal type"
static constexpr command_t commands[2] = {command_t{make_callable(mycommand)},
command_t{make_callable(mycommand2)}};
};
请注意,此处的类型擦除非常有限,因为 lambda 的签名仅因 fun
的捕获签名而异。函数调用显然不需要(也不可能)是 constexpr,只需要构造。
所以基本上我的问题是我能否以某种方式制作 commands
数组 static constexpr
,或者使用 std::function,
或 inplace_function 之类的东西,或者通过我自己的旋转在这种特定情况下类型擦除 lambda 的代码?
由于 mycommanN
具有不同的签名并且您需要捕获它们,所以我看不到有 constexpr 向量的方法。也许有人可以想出更好的设计。
我有一个解决方案:使用 std::tuple
。但我不太喜欢,因为使用 tuple
作为容器真的很麻烦。例如迭代它是……假设不是在公园散步。无论如何,这里是万一它确实有帮助:
using params_t = std::vector<std::variant<int, float /*maybe others*/>>;
// I needed to lift this out of AClass because of ... complicated reasons
// (short version: when both are AClass members
// the return type of `make_command` is not resolved in the init of `commands`
// because both are static, `commands` is not a template and `make_command` is a template
// tbh I don't know exactly what is happening. It's one of those dark corners of C++)
template <class RealFunc>
static constexpr auto make_command(RealFunc real_func) {
return [real_func](params_t params) { /*magic*/ };
}
struct AClass {
static void mycommand();
static void mycommand2(int i);
static constexpr std::tuple commands{make_command(mycommand),
make_command(mycommand2)};
};
// usage
auto test() {
constexpr auto command0 = std::get<0>(AClass::commands<>);
params_t params0 = {};
return command0(command0);
}
一般来说,这是不可能的,因为 lambda 的捕获可以变得任意大,因此,在某些时候我们需要一个堆分配,然后杀死 constexpr pre-C++20 的任何希望(我不也不认为 C++20 对这种情况有多大帮助)。
但是如果我没看错,你只想捕获一个函数指针,我们可以这样做:
#include <vector>
#include<variant>
using params_t = std::vector<std::variant<int, float /*maybe others*/ >>;
struct command_t {
using callable_t = void (*)(std::vector<params_t>);
const callable_t func;
//other members..
};
template<auto f>
void wrap(std::vector<params_t>){
// make this dependent of f, maybe use function_traits for fancy stuff
}
class AClass {
static void mycommand();
static void mycommand2(int i);
static constexpr command_t commands[2] = {wrap<mycommand>, wrap<mycommand2>};
};
int main() {
}
感谢xskxzr的宝贵建议