问题标题的措辞可能不正确,我会很乐意根据您的建议进行修复。
我的问题可以用这个片段来说明:
#include <array>
template <typename Callable>
constexpr auto make_array_ok(Callable callable) {
return std::array<int, callable()>{};
};
// constexpr auto make_array_bad(std::size_t s)
// {
// return std::array<int,s>{};
// };
int main(int argc, char**) {
static_cast<void>(argc);
auto size = []() { return std::size_t{42}; };
// fails to compile -- as I expected
// auto size_dyn = [argc]() { return std::size_t(argc); };
// auto a = make_array_ok(size_dyn);
// also fails to compile -- but why?
// auto size_capt = [arg = size()]()constexpr{return arg;}; …Run Code Online (Sandbox Code Playgroud) 最近,我很惊讶以下代码也在 clang、gcc 和 msvc 中编译(至少在它们当前的版本中)。
struct A {
static const int value = 42;
};
constexpr int f(A a) { return a.value; }
void g() {
A a; // Intentionally non-constexpr.
constexpr int kInt = f(a);
}
Run Code Online (Sandbox Code Playgroud)
我的理解是,调用f不是 constexpr 因为参数i不是,但看来我错了。这是适当的标准支持的代码还是某种编译器扩展?
关键字constexpr在引入 C++11 标准时对其函数实施了相当严格的限制。C++14 和 C++20 放宽了这些限制(最值得注意):
return语句static_assert等。try并且asmC++23 进一步软化了这些限制。从我在cppreference中看到的,constexprfor函数似乎只剩下以下含义:
C++23 甚至删除了 constexpr 函数必须在编译时对于p2448r2中的任何类型“可计算”的限制。根据我的理解,这完全消除了constexpr在编译时评估函数的想法。
是这样吗?如果是这样,constexpr函数还有什么用处呢?
有没有办法编写一个 constexpr 函数来返回 std::vector 的嵌套深度?
例子:
get_vector_nested_layer_count<std::vector<std::vector<int>>>() // 2
get_vector_nested_layer_count<std::vector<std::vector<std::vector<float>>>>() // 3
Run Code Online (Sandbox Code Playgroud) 我正在编写一个简单的 C++ HTTP 服务器框架。在我的Server课堂上,我可以添加Route's。每个路由都包含一个路径、一个 HTTP 方法和一个Controller(这是发出请求时要调用的函数的管道。)该类Controller是通过接收 的列表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\" }]";
},
}
);
Run Code Online (Sandbox Code Playgroud)
既然如此,我想将add_route函数设为 a constexpr,因为如果我错了,请纠正我,constexpr函数可以在编译时执行。
所以,当我做一切的时候constexpr,我发现了以下错误:
Controller.cpp:9:1 constexpr …Run Code Online (Sandbox Code Playgroud) 以下代码无法编译;g++ 7.3.0 with--std=c++17给出了错误信息
constexpr 函数 'constexpr const C operator+(const C&, int)' 的无效返回类型 'const C'
注意:'C' 不是文字,因为 'C' 有一个非平凡的析构函数
#include <string>
using namespace std ;
struct C
{
C (std::string s) : s (s) { }
std::string s ;
} ;
constexpr const C operator+ (const C& x, int y) // <-- Error here
{
return C ("C int") ;
}
int main()
{
C c ("abc") ;
printf ("%s\n", (c + 99).s.c_str()) ;
}
Run Code Online (Sandbox Code Playgroud)
好吧,好吧。但是如果我添加一个看似无关的模板规范到operator+:
template<typename …Run Code Online (Sandbox Code Playgroud) 这是我的代码:
class agg_t1{
int x; // private non-static data menber
};
class agg_t2{
agg_t2(){} // user-provided constructor
};
constexpr void ce1(agg_t1 arg){}; // OK
constexpr void ce2(agg_t2 arg){}; // ERROR: parameter type 'agg_t2' is not a literal type
Run Code Online (Sandbox Code Playgroud)
constexpr 函数的定义应满足以下要求: ...
- 它的每个参数类型都应该是文字类型;...
如果类型是文字类型,则它是: ...
- 它可以是闭包类型、聚合类型,或者......
我理解为什么agg_t2不是文字类型的原因是,它违反了规则dcl.init.aggr#1.1:
聚合是一个数组或一个类......
- 没有用户声明或继承的构造函数...
我认为agg_t1可能不是文字类型,因为它也违反了规则dcl.init.aggr#1.1:
聚合是一个数组或一个类......
- 没有私有或受保护的直接非静态数据成员...
然而......编译器结果告诉我我对 的假设是错误的agg_t1。
如果agg_t1的私有数据成员x …
c++ language-lawyer constant-expression constexpr constexpr-function
通过使用SonarLint分析代码,我收到了一条关于析构函数的消息(问题的标题),其声明如下:
class Foo
{
public:
. // default ctor
. // parameterized ctor
.
inline ~Foo() = default; // dtor
.
. // copy ctor = delete
. // copy assignment operator = delete
. // move ctor
. // move assignment operator
private:
...
mutable std::vector< std::vector<char> > m_Matrix;
...
};
Run Code Online (Sandbox Code Playgroud)
以下是消息的描述: 声明函数或静态成员变量 constexpr 使其隐式内联。
我不认为此类的 dtor 可以是constexprorconsteval因为它具有类型的非静态数据成员std::vector,因此~Foo必须delete[]在某个时刻调用以释放向量的存储。
那么为什么SonarLint显示此消息呢?是因为吗 = default?是否有任何 …
c++ destructor inline-functions sonarlint constexpr-function
经过两三天的尝试,我不得不放弃并编写了一个“最小”测试用例,希望能够证明该问题。
我需要的是一种将字符串文字(作为不带引号的宏参数传递)转换为可在 constexpr 环境中访问的字符串(用前缀连接)的方法(请参阅https://wandbox.org/permlink/Cr6j6fXemsQRycHI真实代码( tm));这意味着,它们(宏参数)应该被字符串化,然后转换为类型(例如 template <... 'h', 'e', 'l', 'l', 'o', ...>)或转换为static constexpr array<char, N>传递的唯一类型的 a (例如 template <... A<1> ...>,其中A<1>::strastatic constexpr array<char, 6>包含内容'h', 'e', 'l', 'l', 'o', '\0'.
我强烈喜欢后者,只有当后者不可能时才选择前者。
为了在简短的测试用例中演示确切的问题/要求,我提出了以下内容:
一些标题...
#include <array>
#include <tuple>
#include <cassert>
#include <string>
#include <iostream>
Run Code Online (Sandbox Code Playgroud)
然后为了演示最终结果应该如何表现:
template<int I>
struct A;
template<>
struct A<0>
{
static constexpr auto str = std::to_array("abc"); // The string-literal "abc" may NOT appear here.
// …Run Code Online (Sandbox Code Playgroud) 我有这样的代码:
template<typename ... Args>
constexpr size_t get_init_size(Args ... args) {
return sizeof...(Args);
}
template<typename ... Args>
constexpr auto make_generic_header(Args ... args) {
constexpr size_t header_lenght = get_init_size(args...);
return header_lenght;
}
constexpr auto create_ipv4_header() {
constexpr auto x = make_generic_header(0b01, 0b10, 0b01);
return x;
}
Run Code Online (Sandbox Code Playgroud)
我知道这是虚拟代码,但我将其隔离以查找错误。
编译器给我错误(GCC):
In instantiation of 'constexpr auto make_generic_header(Args&& ...) [with Args = {int, int, int}]':
/tmp/tmp.CaO5YHcqd8/network.h:39:43: required from here
/tmp/tmp.CaO5YHcqd8/network.h:31:22: error: 'args#0' is not a constant expression
31 | constexpr size_t header_lenght = get_init_size(args...);
| ^~~~~~~~~~~~~ …Run Code Online (Sandbox Code Playgroud)