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);
}
错误: constexpr函数的主体'constexpr T getClamped(const T&amp;,const T&amp;,const T&amp;)[with T = long unsigned int]'< strong>不是退货声明
使用g++ 4.8.1
。 clang++ 3.4
不会抱怨。
谁在这?我可以用g++
编译代码而不使用宏吗?
答案 0 :(得分:13)
#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));
}
我们滥用逗号运算符两次。
第一次因为我们想要assert
,true
可以从constexpr
函数调用constexpr
。第二个,所以我们可以将两个函数链接成一个constexpr_assert
函数。
另一个好处是,如果在编译时无法将true
表达式验证为getClamped
,则constexpr
函数不是assert_helper
。
assert
存在是因为NDEBUG
的内容是constexpr_assert
为真时的实现定义,因此我们无法将其嵌入到表达式中(它可以是语句,而不是表达式) 。即使constexpr
为assert
(例如,当constexpr
为假时),它也可以保证失败的NDEBUG
无法{{1}}。
所有这一切的缺点是你的断言不是在问题发生的那一行发射,而是2次更深的呼叫。
答案 1 :(得分:5)
从C ++ 14开始,这不再是一个问题;带有g++
标志的-std=c++14
可以编译并运行您的代码。
有三个缺点:
assert
永远不会在编译时被触发。即使添加具有相同条件的static_assert
也不会有效,因为mMin
和mMax
不被视为常量表达式。assert
在编译时没有被触发,但是函数是constexpr
,如果条件是 false 但是表达式在编译时进行评估(例如constexpr auto foo = getClamped(1,2,0);
),assert
将从不触发 - 意味着不会捕获不正确的函数参数。在评论中,用户oliora链接到interesting blog post by Eric Niebler,该variation of this approach描述了在C ++ 11中工作的多种方法和可以在编译时或在运行时适当时触发。
简而言之,策略是:
throw
例外;要使其无法捕获(即更像assert
),请标记constexpr
函数nothrow
throw
表达式必须包含在仅评估的某种更大的逻辑表达式中assert
ed的条件是false
,例如三元表达式(这是Niebler在他的例子中使用的)。即使在C ++ 14中,也允许单独的if (condition) throw <exception>;
语句不。assert
不同,此方法不依赖于NDEBUG
;发布版本将触发失败并崩溃。std::quick_exit
。这消除了对nothrow
的需求。
quick_exit
电话打包在ifdef
中)。assert
,该lambda传递给一个采用任意可调用的结构(作为模板参数)并调用它,然后调用std::quick_exit
,然后调用{{1}那个结构。这个似乎是严重的过度杀伤,但当然它会在运行时生成一个真正的断言失败消息,这很好。
throw
和throw
。这似乎更清洁,更健全。答案 2 :(得分:3)
constexpr在编译时计算。非静态断言在运行时。
答案 3 :(得分:1)
g ++是对的。根据标准,assert
语句中不允许使用非静态constexpr
。
...它的函数体应该是一个只包含的复合语句:
空陈述,
static_assert申述,
typedef声明和不定义类或枚举的别名声明,
使用申述,
using指令,
并且只有一个回报声明 - 7.1.5 / 3