Vit*_*meo 9 c++ assert g++ constexpr c++11
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);
}
Run Code Online (Sandbox Code Playgroud)
错误:constexpr函数的主体 'constexpr T getClamped(const T&,const T&,const T&)[with T = long unsigned int]' not return-statement
用g++ 4.8.1.clang++ 3.4不抱怨
谁在这?我可以g++在不使用宏的情况下编译代码吗?
Yak*_*ont 13
GCC是对的.但是,有一个相对简单的解决方法:
#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));
}
Run Code Online (Sandbox Code Playgroud)
我们滥用逗号运算符的地方,两次.
第一次,因为我们希望有一个assert,何时true,可以从一个constexpr函数调用.第二,所以我们可以将两个函数链接成一个constexpr函数.
作为附带好处,如果constexpr_assert表达式无法true在编译时验证,则getClamped函数不是constexpr.
的assert_helper存在,因为内容assert是当实现定义NDEBUG是真实的,所以我们不能把它嵌入到一个表达式(它可能是一个声明,而不是一个表达式).这也保证了失败的constexpr_assert失败是constexpr即使assert是constexpr(比方说,如果NDEBUG是假的).
所有这一切的缺点是你的断言不是在发生问题的行发射,而是2次调用更深.
从C++ 14开始,这不再是一个问题; g++用-std=c++14旗子编译并运行你的代码就好了.
有三个缺点:
assert意志,当然,从来没有在编译时触发.即使添加static_assert具有相同条件的a也不起作用,因为mMin并且mMax不被视为常量表达式.assert没有在编译时触发,但功能是constexpr,如果条件是假的,但表达的是在编译时(例如计算constexpr auto foo = getClamped(1,2,0);)中,assert将永远不会火-这意味着不正确的函数参数不会被抓.在评论中,用户oliora链接到Eric Niebler撰写的一篇有趣的博客文章,其中描述了在C++ 11中有效的多种方法,并且可以在编译时或在运行时适当时触发.
简而言之,策略是:
throw例外; 要使其无法捕捉(即更像是assert),请标记该constexpr功能nothrow
throw表达式必须包含在某种更大的逻辑表达式中,只有当条件被assert编辑时才会被评估false,例如三元表达式(这是Niebler在他的例子中使用的).一个独立的if (condition) throw <exception>;声明将不会被允许的,即使在C++ 14.assert此不同,这种方法并不依赖于NDEBUG; 发布版本将触发失败和崩溃.std::quick_exit.这消除了对nothrow.
quick_exit调用ifdef).assert内部包装在一个lambda中,该lambda传递给一个带有任意可调用的结构(作为模板参数)并调用它然后调用std::quick_exit,然后调用throw该结构.这个似乎是严重的过度杀伤,但当然它会在运行时生成一个真正的断言失败消息,这很好.