Constexpr可构造函数对象

问题描述 投票:3回答:2

我有一个与this one有点类似的问题,但是对于一个更有限的情况,我认为应该可以以某种方式实现:我想从多个lambda构造函数调用的静态constexpr数组,每个lambda共享相同的签名。静态和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)}};
};

On coliru

注意,这里的类型擦除非常有限,因为lambda的签名仅根据fun捕获的签名而变化。函数调用显然不需要(也不需要)是constexpr,只需构造即可。

所以,基本上我的问题是我可以以某种方式使用commands或类似static constexpr的方式来制作std::function,数组inplace_function,或者在这种特定情况下,可以通过旋转我自己的代码来对lambda进行类型擦除?

我有一个与此问题有些类似的问题,但是对于一个更有限的情况,我认为应该可以以某种方式实现:我想从多个...]构造一个函数调用的静态constexpr数组。] >> [[

由于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可以变得任意大,因此,在某些时候,我们需要堆分配,这将使C ++ 20之前的constexpr失去希望(我不认为对于这种情况,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的宝贵建议。
c++ c++17 constexpr type-erasure std-function
2个回答
0
投票
由于mycommanN具有不同的签名,您需要捕获它们,所以我看不到拥有constexpr向量的方法。也许有人可以提出更好的设计。

0
投票
通常,这是不可能的,因为捕获的lambda可以变得任意大,因此,在某些时候,我们需要堆分配,这将使C ++ 20之前的constexpr失去希望(我不认为对于这种情况,C ++ 20都会有很大帮助)。

但是如果我看对了,并且我们可以做到,您只想捕获一个函数指针:

© www.soinside.com 2019 - 2024. All rights reserved.