constexpr 构造函数的参数类型 'std::function' 不是文字类型
constexpr constructor's parameter type 'std::function' is not a literal type
我正在编写一个简单的 C++ HTTP 服务器框架。在我的 Server
class 中,我可以添加 Route
的。每个路由都包含一个路径、一个 HTTP 方法和一个 Controller
(这是发出请求时要调用的函数管道。)Controller
class 是通过接收一个std::function
的列表(或者更准确地说:std::function<void(const HTTPRequest&, HTTPResponse&, Context&)>
),但大多数时候(或者我应该说 每次 次),这个 Controller
将使用 lambda 函数文字列表进行初始化,如以下代码所示:
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, auto&) {
response << "{ \"test2\": \"2\" }]";
},
}
);
既然如此,我想把add_route
函数改成constexpr
,因为,如果我错了请指正,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
class 的代码。我知道还有其他编译错误,但这是我现在要解决的主要问题。提前致谢!
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&, HTTPResponse&, 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&, HTTPResponse&, Context&);
};
controller.cpp
#include "controller.hpp"
template <size_t N>
auto Controller<N>::empty_controller() -> Controller<1> {
return Controller<1>([](auto, auto, auto) {});
}
template <>
constexpr Controller<1>::Controller(Callable _callable) :
callables(std::array<Callable, 1> { std::move(_callable) }) { }
template <>
constexpr Controller<1>::Controller() :
Controller(empty_controller()) { }
template <size_t N>
constexpr Controller<N>::Controller(std::initializer_list<Callable> _list_callables) :
callables(_list_callables) { }
template <size_t N>
void Controller<N>::call(const HTTPRequest& req, HTTPResponse& res, Context& ctx) {
for (auto& callable : callables) {
callable(req, res, ctx);
}
}
why std::function's can't be literal types? Is there any way to circumvent this limitation?
因为它使用类型擦除来接受任何可调用对象。这需要多态性,它在 C++20 之前不能是 constexpr,它将允许 constexpr virtual
。
您可以使用模板并直接捕获可调用对象,但它的类型会蔓延到 Controller
并进一步传播。
Being this the case, I would like to make the add_route function a constexpr, because, correct me if I am wrong, constexpr functions can be executed at compile time.
是的,如果给定 constexpr
个参数,函数将在compile-time 处执行。看它像高级常量折叠。此外,在 compile-time 上下文中使用的 constexpr
方法要么无法访问 *this
,要么是 constexpr。特别是,constexpr
方法只能在编译时改变 constexpr
实例的状态。否则该函数通常在 运行 时间 运行。
最后一点与您相关,运行在 compile-time 设置 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;
}
我正在编写一个简单的 C++ HTTP 服务器框架。在我的 Server
class 中,我可以添加 Route
的。每个路由都包含一个路径、一个 HTTP 方法和一个 Controller
(这是发出请求时要调用的函数管道。)Controller
class 是通过接收一个std::function
的列表(或者更准确地说:std::function<void(const HTTPRequest&, HTTPResponse&, Context&)>
),但大多数时候(或者我应该说 每次 次),这个 Controller
将使用 lambda 函数文字列表进行初始化,如以下代码所示:
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, auto&) {
response << "{ \"test2\": \"2\" }]";
},
}
);
既然如此,我想把add_route
函数改成constexpr
,因为,如果我错了请指正,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
class 的代码。我知道还有其他编译错误,但这是我现在要解决的主要问题。提前致谢!
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&, HTTPResponse&, 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&, HTTPResponse&, Context&);
};
controller.cpp
#include "controller.hpp"
template <size_t N>
auto Controller<N>::empty_controller() -> Controller<1> {
return Controller<1>([](auto, auto, auto) {});
}
template <>
constexpr Controller<1>::Controller(Callable _callable) :
callables(std::array<Callable, 1> { std::move(_callable) }) { }
template <>
constexpr Controller<1>::Controller() :
Controller(empty_controller()) { }
template <size_t N>
constexpr Controller<N>::Controller(std::initializer_list<Callable> _list_callables) :
callables(_list_callables) { }
template <size_t N>
void Controller<N>::call(const HTTPRequest& req, HTTPResponse& res, Context& ctx) {
for (auto& callable : callables) {
callable(req, res, ctx);
}
}
why std::function's can't be literal types? Is there any way to circumvent this limitation?
因为它使用类型擦除来接受任何可调用对象。这需要多态性,它在 C++20 之前不能是 constexpr,它将允许 constexpr virtual
。
您可以使用模板并直接捕获可调用对象,但它的类型会蔓延到 Controller
并进一步传播。
Being this the case, I would like to make the add_route function a constexpr, because, correct me if I am wrong, constexpr functions can be executed at compile time.
是的,如果给定 constexpr
个参数,函数将在compile-time 处执行。看它像高级常量折叠。此外,在 compile-time 上下文中使用的 constexpr
方法要么无法访问 *this
,要么是 constexpr。特别是,constexpr
方法只能在编译时改变 constexpr
实例的状态。否则该函数通常在 运行 时间 运行。
最后一点与您相关,运行在 compile-time 设置 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;
}