constexpr构造函数的参数类型'std :: function'不是文字类型 编辑constexpr行为示例

问题描述

我正在编写一个简单的C ++ HTTP服务器框架。在我的Server类中,可以添加Route。每个路由都包含一个路径,一个HTTP方法一个Controller(这是在发出请求时要调用函数的管道。)Controller类是通过接收{{ 1}}(或更精确地说:std::function),但是在大多数情况下(或者我应该说每次时间),此std::function<void(const HTTPRequest&,HTTPResponse&,Context&)>会使用lambda函数文字列表,如以下代码所示:

Controller

在这种情况下,我想将server.add_route("/",HTTPMethod::GET,{ [](auto,auto& response,auto&) { const int ok = 200; response.set_status(ok); response << "[{ \"test1\": \"1\" },"; response["Content-Type"] = "text/json; charset=utf-8"; },[](auto,auto&) { response << "{ \"test2\": \"2\" }]"; },} ); 函数设为add_route,因为如果我错了,请纠正我,constexpr函数可以在编译时执行。 / p>

因此,当我做所有constexpr时,发现以下错误

constexpr

我想知道的是:为什么Controller.cpp:9:1 constexpr constructor's 1st parameter type 'Callable' (aka 'function<void (const HTTPRequest &,HTTPResponse &,Context &)>') is not a literal type 不能是文字类型?有什么办法可以规避这一限制?

下面是std::function类的代码。我知道仍然存在其他编译错误,但这是我现在要解决的主要问题。预先感谢!

Controller

controller.hpp

#pragma once #include <functional> #include <initializer_list> #include <vector> #include "context.hpp" #include "httprequest.hpp" #include "httpresponse.hpp" typedef std::function<void(const HTTPRequest&,Context&)> Callable; template <size_t N> class Controller { private: std::array<Callable,N> callables; public: static auto empty_controller() -> Controller<1>; constexpr explicit Controller(Callable); constexpr Controller(); constexpr Controller(std::initializer_list<Callable>); void call(const HTTPRequest&,Context&); };

controller.cpp

解决方法

为什么std :: function不能是文字类型?有什么办法可以规避这一限制?

因为它使用类型擦除来接受任何可调用对象。这需要在C ++ 20允许constexpr virtual之前不能是constexpr的多态性。 您可以使用模板并直接捕获可调用对象,但是其类型将蔓延到Controller中并进一步传播。

在这种情况下,我想使add_route函数成为constexpr,因为如果我错了,请更正我,可以在编译时执行constexpr函数。

是,如果给定 constexpr参数,则该函数将在编译时执行。像高级连续折叠一样看它。此外,在编译时上下文中使用的constexpr方法不能访问*this或也必须是constexpr。特别是,constexpr方法只能在编译时更改constexpr实例的状态。否则,该函数通常在运行时运行。

最后一点与您有关,在编译时运行HTTP服务器几乎没有任何意义,因此constexpr可能不需要,也无济于事。

编辑constexpr行为示例

struct Foo{
    //If all members are trivial enough and initialized,the constructor is constexpr by default.
    int state=10;
    //constexpr Foo()=default;
constexpr int bar(bool use_state){
    if(use_state)
        return state++;
    else
        return 0;// Literal
}
constexpr int get_state()const{
    return state;
}
};

template<int arg>
void baz(){}
int main(int argc,char* argv[])
{
   Foo foo;
   //Carefull,this also implies const and ::bar() is non-const.
   constexpr Foo c_foo;

   foo.bar(true);//Run-time,`this` is not constexpr even though `true` is
   foo.bar(false);//Compile-time,`this` was not needed,`false` is constexpr

   bool* b = new bool{false};
   foo.bar(*b);//Always run-time since `*b` is not constexpr



   //Force compile-time evaluation in compile-time context
   //Foo has constexpr constructor,creates non-const (temporary) constexpr instance
   baz<Foo().bar(true)>();
   baz<Foo().bar(false)>();
   baz<foo.bar(false)>();
   //ERROR,foo is not constexpr
   //baz<foo.bar(true)>();
   //ERROR,c_foo is const
   //baz<c_foo.bar(false)>();
   //Okay,c_foo is constexpr
   baz<c_foo.get_state()>();
   //ERROR,foo is not constexpr
   //baz<foo.get_state()>();

    return 0;
}