[英]g++ doesn't compile constexpr function with assert in it
template<typename T> constexpr inline
T getClamped(const T& mValue, const T& mMin, const T& mMax)
{
assert(mMin < mMax); // remove this line to successfully compile
return mValue < mMin ? mMin : (mValue > mMax ? mMax : mValue);
}
error : body of constexpr function 'constexpr T getClamped(const T&, const T&, const T&) [with T = long unsigned int]' not a return-statement
错误 : constexpr函数的主体 'constexpr T getClamped(const T&,const T&,const T&)[with T = long unsigned int]' not return-statement
Using g++ 4.8.1
. 使用
g++ 4.8.1
。 clang++ 3.4
doesn't complain. clang++ 3.4
不抱怨。
Who is right here? 谁在这? Any way I can make
g++
compile the code without using macros? 我可以用
g++
编译代码而不使用宏吗?
GCC is right. GCC是对的。 However, there is a relatively simple workaround:
但是,有一个相对简单的解决方法:
#include "assert.h"
inline void assert_helper( bool test ) {
assert(test);
}
inline constexpr bool constexpr_assert( bool test ) {
return test?true:(assert_helper(test),false);
}
template<typename T> constexpr
inline T getClamped(const T& mValue, const T& mMin, const T& mMax)
{
return constexpr_assert(mMin < mMax), (mValue < mMin ? mMin : (mValue > mMax ? mMax : mValue));
}
where we abuse the comma operator, twice. 我们滥用逗号运算符的地方,两次。
The first time because we want to have an assert
that, when true
, can be called from a constexpr
function. 第一次因为我们想要一个
assert
,当为true
,可以从constexpr
函数调用。 The second, so we can chain two functions into a single constexpr
function. 第二个,所以我们可以将两个函数链接到一个
constexpr
函数中。
As a side benefit, if the constexpr_assert
expression cannot be verified to be true
at compile time, then the getClamped
function is not constexpr
. 作为附带好处,如果在编译时无法验证
constexpr_assert
表达式为true
,则getClamped
函数不是constexpr
。
The assert_helper
exists because the contents of assert
are implementation defined when NDEBUG
is true, so we cannot embed it into an expression (it could be a statement, not an expression). assert_helper
存在是因为当NDEBUG
为true时, assert
的内容是实现定义的,所以我们不能将它嵌入到表达式中(它可以是一个语句,而不是一个表达式)。 It also guarantees that a failed constexpr_assert
fails to be constexpr
even if assert
is constexpr
(say, when NDEBUG
is false). 它还保证即使
assert
是constexpr
(例如,当NDEBUG
为false时), constexpr_assert
失败也不能成为constexpr
。
A downside to all of this is that your assert fires not at the line where the problem occurs, but 2 calls deeper. 所有这一切的缺点是你的断言不是在发生问题的行发射,而是2次调用更深。
As of C++14, this is no longer an issue; 从C ++ 14开始,这不再是一个问题;
g++
with the -std=c++14
flag compiles and runs your code just fine. 带有
-std=c++14
标志的g++
编译并运行你的代码就好了。
There are three drawbacks: 有三个缺点:
assert
will, of course, never by triggered at compile time. assert
永远不会在编译时触发。 Even adding a static_assert
with the same condition won't work, since mMin
and mMax
are not considered constant expressions. static_assert
也不起作用,因为mMin
和mMax
不被视为常量表达式。 assert
isn't triggered at compile time, but the function is constexpr
, if the condition is false but the expression is evaluated at compile time (eg constexpr auto foo = getClamped(1,2,0);
), the assert
will never fire--meaning that the incorrect function arguments will not be caught. assert
未在编译时触发,但功能是constexpr
,如果条件为假 ,但在编译时表达式进行求值(例如constexpr auto foo = getClamped(1,2,0);
),则assert
永远不会触发 - 意味着不会捕获不正确的函数参数。 In a comment, user oliora links to an interesting blog post by Eric Niebler that describes multiple approaches that work in C++11 and can be triggered while compiling or at runtime as appropriate. 在评论中,用户oliora链接到Eric Niebler撰写的一篇有趣的博客文章,其中描述了在C ++ 11中有效的多种方法, 并且可以在编译时或在运行时适当时触发。
In short, the strategies are: 简而言之,策略是:
throw
an exception; throw
异常; to make it uncatchable (ie more like an assert
), mark the constexpr
function nothrow
assert
),标志着constexpr
函数nothrow
throw
expression must be wrapped in some kind of larger logical expression that is only evaluated if the condition being assert
ed is false
, such as a ternary expression (which is what Niebler uses in his example). throw
表达式必须包含在某种更大的逻辑表达式中, 只有在被assert
的条件为false
才会被计算,例如三元表达式(这是Niebler在他的用法中使用的)例)。 A standalone if (condition) throw <exception>;
if (condition) throw <exception>;
statement will not be permitted, even in C++14. assert
, this approach does not depend on NDEBUG
; assert
不同,这种方法不依赖于NDEBUG
; release builds will trigger failures and crash. std::quick_exit
. std::quick_exit
。 This eliminates the need for nothrow
. nothrow
的需要。
quick_exit
call in ifdef
's). ifdef
包装quick_exit
调用)。 assert
inside a lambda, which is passed to a struct that takes an arbitrary callable (as a template parameter) and invokes it and then calls std::quick_exit
, and then throw
that struct. assert
,它传递给一个带有任意可调用的结构(作为模板参数)并调用它,然后调用std::quick_exit
,然后throw
该结构。 This one seems like severe overkill, but of course it generates a true assertion-failure message at runtime, which is nice. throw
and the quick_exit
. throw
和quick_exit
。 This seems much cleaner and saner. constexpr calculates in compile time. constexpr在编译时计算。 Non static assert in run-time.
非静态断言在运行时。
g++ is right. g ++是对的。 Per the standard, a non-static
assert
is not permitted in a constexpr
statement. 根据标准,
constexpr
语句中不允许使用非静态assert
。
... its function-body shall be a compound-statement that contains only:
...其函数体应为仅包含以下内容的复合语句:
null statements,空语句,
static_assert-declarations,static_assert申述,
typedef declarations and alias-declarations that do not define classes or enumerations,typedef声明和不定义类或枚举的别名声明,
using-declarations,使用申述,
using-directives,using指令,
and exactly one return statement.而且只有一个退货声明。
-- 7.1.5/3- 7.1.5 / 3
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.