C++ 标准要求编译器检查C++ constexpr 计算中未定义的行为。
在这次演讲中,Chandler Carruth 指出,在检查 UB 时“你将耗尽检测错误的能力”,并且在一般情况下,检测 UB 与停机问题有关,因此证明不可能做出决定。
他不是在谈论 constexpr 中的 UB,但constexpr 计算与自 C++14 以来的常规程序一样通用,因此这仍然适用。
那么,当编译器无法确定程序是否是 UB 时,他们会做什么呢?他们是否仍然接受该程序并继续编译?或者他们是否更加保守并拒绝该计划,即使它可能是正确的?(我个人的感觉是他们这样做)
对我来说,这具有实际意义,因为我使用非平凡的指针算术进行了 constexpr 评估,用 Clang 编译得很好,但用 GCC 编译失败,而且我很确定这不是 UB。你可以说这是一个 GCC bug,但是如果 UB 是不可判定的,那么所有编译器在这方面都会存在 bug。
更根本的是,为什么标准要求不含 UB ?有技术原因吗?或者更多的是一种哲学(“如果编译器无法检查,程序员可以触发 UB,就会导致不好的结果”)?
我认为这与 C++ 的其余部分不一致,这永远不会阻止你搬起石头砸自己的脚。我希望 GCC 接受我的 constexpr 代码并崩溃,或者如果 UB 则发出垃圾;而不是在不知道是否是UB的情况下不编译。
====== 编辑======
正如 MM 和 Nicol Bolas 所指出的,该标准指定了限制(即使在 C++14 中也是如此),因此我们永远不会陷入 UB 的停止问题类型。然而,我仍然想知道检查 UB 是否可能太复杂,并且如果编译器启发式失败,那么它们会将其标记为非 constexpr(可能是错误的)。
但从评论中我感觉这更多是一个不成熟的实现问题。
在 C++14 及更高版本中,constexprfor 成员函数不再意味着const。
struct Value\n{\n int i = 5;\n\n constexpr bool not_five() // requires const to compile\n {\n return this->i != 5;\n }\n};\n\nint main()\n{\n constexpr Value v{6};\n static_assert(v.not_five());\n}\nRun Code Online (Sandbox Code Playgroud)\n\nerror: passing \xe2\x80\x98const Value\xe2\x80\x99 as \xe2\x80\x98this\xe2\x80\x99 argument discards qualifiers [-fpermissive]\n static_assert(v.not_five());\n ^\nRun Code Online (Sandbox Code Playgroud)\n\n似乎在编译时调用非常量 constexpr 成员函数意味着常量的突变,因为它所调用的对象在编译时存在并且正在发生突变。非常量 constexpr 成员函数的概念在什么情况下有用?
\n我想换constexpr-ops-limit一个更大的数字。我知道可以作为-fconstexpr-ops-limit=命令行参数,但我无法更改参数,因为我将代码提交到自动运行它的系统。我想知道 GCC 或 VC++ 中是否有任何编译指示可以满足我的需求。
有什么办法可以做到吗?先感谢您。
环境:VS 2019,v16.4.3 w/c++17 + 最新开关
以下代码标准是否正确,还是我做错了什么?它使用最新的 gcc/clang 编译器可以正常编译,但在 MSVC 上失败。(请参阅下面的错误消息)
template<typename T>
struct mixin {};
struct thing : mixin<thing>
{
constexpr explicit thing(int value) : value_(value) {}
constexpr int value() const { return value_; }
private:
int value_ = 0;
};
template<typename T>
constexpr auto do_mixin_thing(mixin<T> const& m)
{
return static_cast<T const&>(m).value() * 10;
}
int main()
{
constexpr thing t1{ 10 };
// this works
static_assert(t1.value() == 10);
// this fails
static_assert(do_mixin_thing(t1) == 100);
}
Run Code Online (Sandbox Code Playgroud)
这是输出:
error C2131: expression …Run Code Online (Sandbox Code Playgroud) 基本思想是这样的:我有一些constexpr函数,我想用它throw来发出错误信号和延迟编译以避免正常流程中出现此错误:
template <size_t N>
auto constexpr find_elt(const std::array<int, N>& a, int k) {
for (size_t i = 0; i < N; ++i)
if (k == a[i])
return i;
throw "not found";
}
Run Code Online (Sandbox Code Playgroud)
进而:
constexpr int result = find_elt(arr, 4);
Run Code Online (Sandbox Code Playgroud)
通常,如果数组中存在 4,我将在编译时获取其索引。
如果没有,我就会陷入困境throw编译时的查找是错误的,并且编译器将产生一个漂亮的错误。
但我注意到奇怪的行为:
这个想法合法吗?这段代码对于我想要实现的目标是否正确?哪个编译器在这里告诉我真相?
如果不是,正确的方法是什么?
任何到 C++ 标准的链接都值得赞赏。我通读了 constexpr 相关的章节,但我有疑问。
今天有人请我帮忙做一个用 G++ 编译的 VC++ 项目,我偶然发现了这一行:
static char data[constexpr(sizeof(T))];
Run Code Online (Sandbox Code Playgroud)
(当然,它位于带有名为 的模板参数的模板函数内T)。
我没有 C++ 标准,但根据cppreference:
句法
sizeof( 类型 ) (1)
表达式的大小 (2)
两个版本都是 std::size_t 类型的常量表达式。
sizeof()那么告诉 VC++预期的结果有什么意义呢constexpr?
尝试一下: https: //rextester.com/VIWP36674。
正如预期的那样,在 VC 上有效,但在 G++ 上失败。
另一种尝试选择: https: //godbolt.org/z/DnioLS
适用于 VC 直至 19.10。似乎是在 19.14 修复的,所以我认为这确实是一个怪癖,但即使如此,也一定有人有理由编写这样的代码......
我已经读过这篇文章,但我仍然不知道如何使其工作,-std=gnu++2a
我不知道如何使用integer seq。您能帮我修改下面的代码以便它可以编译吗?谢谢
constexpr bool example(const int k)
{
return k < 23 ? true: false;
}
constexpr bool looper()
{
constexpr bool result = false;
for(int k = 0; k < 20; k ++)
{
for (int i = 0 ; i < k; ++i)
{
constexpr bool result = example(i);
}
}
return result;
}
int main()
{
constexpr bool result = looper();
return 0;
}
Run Code Online (Sandbox Code Playgroud) 我想检查一个函数是否可以在编译期间被评估。我发现了这个,但我不完全理解这个概念。我有几个疑问:
代码中下面这行的作用是什么?
template<int Value = Trait::f()>
每次当我需要检查该函数是否可以在编译时评估时,是否需要将其设为某个结构的成员函数?
PS
我复制链接中的代码,只是为了方便。
template<typename Trait>
struct test
{
template<int Value = Trait::f()>
static std::true_type do_call(int){ return std::true_type(); }
static std::false_type do_call(...){ return std::false_type(); }
static bool call(){ return do_call(0); }
};
struct trait
{
static int f(){ return 15; }
};
struct ctrait
{
static constexpr int f(){ return 20; }
};
int main()
{
std::cout << "regular: " << test<trait>::call() << std::endl;
std::cout << "constexpr: " << test<ctrait>::call() << std::endl;
}
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) 我对constexpr编程比较陌生,正在尝试string_view在constexpr上下文中对对象进行一些基本操作。就我而言,所有字符串在我的源代码中都以文字开头,因此它们似乎应该是常量表达式。我发现我可以constexpr string_view从字符串文字构造 a ,没有任何问题。
但是,如果我尝试调用一个采用字符串文字作为参数的constexpr函数,则编译会失败。string_view请参阅以下示例(编译器资源管理器链接):
#include <string_view>
// this doesn't compile; the compiler complains that `sv` is not a constant-expression
constexpr bool foo(std::string_view sv)
{
constexpr auto it = sv.find('b');
return it != sv.end();
}
// this compiles just fine, though
constexpr std::string_view bar("def");
int main()
{
foo("abc");
}
Run Code Online (Sandbox Code Playgroud)
gcc 8.3 提供以下错误:
<source>: In function 'constexpr bool foo(std::string_view)':
<source>:5:32: in 'constexpr' expansion of 'sv.std::basic_string_view<char>::find(((int)'b'), 0)'
<source>:5:36: …Run Code Online (Sandbox Code Playgroud)