Dav*_*one 13 c++ inline static-assert constexpr c++11
我之前根据参数是否constexpr询问函数重载.我正试图解决这个问题的令人失望的答案,以建立一个更聪明的断言功能.这大致是我想做的事情:
inline void smart_assert (bool condition) {
if (is_constexpr (condition))
static_assert (condition, "Error!!!");
else
assert (condition);
}
Run Code Online (Sandbox Code Playgroud)
基本上,我们的想法是编译时检查总是比运行时检查更好,如果可以在编译时检查.但是,由于内联和常量折叠之类的东西,我不能总是知道是否可以进行编译时间检查.这意味着可能存在assert (condition)编译的情况,assert(false)代码只是等待我运行它并在我发现错误之前执行该路径.
因此,如果有某种方法来检查条件是否是constexpr(由于内联或其他优化),我可以static_assert在可能的情况下调用,否则返回运行时断言.幸运的是,gcc具有内在函数__builtin_constant_p (exp),如果exp是constexpr 则返回true .我不知道其他编译器是否有这种内在的,但我希望这可以解决我的问题.这是我提出的代码:
#include <cassert>
#undef IS_CONSTEXPR
#if defined __GNUC__
#define IS_CONSTEXPR(exp) __builtin_constant_p (exp)
#else
#define IS_CONSTEXPR(exp) false
#endif
// TODO: Add other compilers
inline void smart_assert (bool const condition) {
static_assert (!IS_CONSTEXPR(condition) or condition, "Error!!!");
if (!IS_CONSTEXPR(condition))
assert (condition);
}
#undef IS_CONSTEXPR
Run Code Online (Sandbox Code Playgroud)
该static_assert依靠的短路行为or.如果IS_CONSTEXPR为真,则static_assert可以使用,条件是!true or condition,与刚刚相同condition.如果IS_CONSTEXPR为false,则static_assert不能使用,条件是!false or condition,它是相同的,true并且static_assert被忽略.如果static_assert因为condition不是constexpr 而无法检查,那么我assert在我的代码中添加一个运行时作为最后的努力.但是,由于无法在a中使用函数参数static_assert,即使参数是constexpr,也不起作用.
特别是,如果我尝试使用gcc编译,会发生这种情况:
// main.cpp
int main () {
smart_assert (false);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
g++ main.cpp -std=c++0x -O0
一切都很好,正常编译.没有内联没有优化,所以IS_CONSTEXPR是false并且static_assert被忽略,所以我得到一个运行时assert语句(失败).然而,
[david@david-desktop test]$ g++ main.cpp -std=c++0x -O1
In file included from main.cpp:1:0:
smart_assert.hpp: In function ‘void smart_assert(bool)’:
smart_assert.hpp:12:3: error: non-constant condition for static assertion
smart_assert.hpp:12:3: error: ‘condition’ is not a constant expression
Run Code Online (Sandbox Code Playgroud)
一旦我打开任何优化并因此可能允许static_assert被触发,它就会失败,因为我不能在中使用函数参数static_assert.有没有办法解决这个问题(即使它意味着实现我自己的static_assert)?我觉得我的C++项目理论上可以从一个更聪明的断言声明中获益,它尽可能早地捕获错误.
smart_assert在一般情况下,制作类似函数的宏似乎不会解决问题.它显然会使它在这个简单的例子中起作用,但condition可能来自调用图的两个级别的函数(但constexpr由于内联而仍然被编译器知道),这遇到了使用函数参数的相同问题在一个static_assert.
这应该可以帮助你开始
template<typename T>
constexpr typename remove_reference<T>::type makeprval(T && t) {
return t;
}
#define isprvalconstexpr(e) noexcept(makeprval(e))
Run Code Online (Sandbox Code Playgroud)
一般而言,明确是好的,隐含是坏的.
程序员总是可以试试static_assert.
如果在编译时无法评估条件,那么失败,程序员需要更改为assert.
您可以通过提供一个通用表单来更容易地做到这一点,以便更改减少到例如STATIC_ASSERT( x+x == 4 )→ DYNAMIC_ASSERT( x+x == 4 ),只是重命名.
也就是说,因为在你的情况下你只想优化程序员的时间,如果可用的优化,即因为你可能不关心总是与所有编译器得到相同的结果,你总是可以尝试像...
#include <iostream>
using namespace std;
void foo( void const* ) { cout << "compile time constant" << endl; }
void foo( ... ) { cout << "hm, run time,,," << endl; }
#define CHECK( e ) cout << #e << " is "; foo( long((e)-(e)) )
int main()
{
int x = 2134;
int const y = 2134;
CHECK( x );
CHECK( y );
}
Run Code Online (Sandbox Code Playgroud)
如果你这样做,那么请告诉我们它是如何淘汰的.
注意:上面的代码确实在MSVC 10.0和g ++ 4.6中产生了不同的结果.
更新:我想知道如何评论上面的代码是如何工作的,得到了如此多的赞成.我想也许他说的是我根本不懂的东西.所以我开始做OP的工作,检查这个想法的表现.
在这一点上我认为,如果该constexpr功能的东西,可以进行与G ++的工作,那么它可能也是解决问题的G ++,否则,只能为其他编译器.
以上是我对g ++支持的支持.使用我提出的想法,这适用于Visual C++,可以很好地解决(解决OP的问题).但不是用g ++:
#include <assert.h>
#include <iostream>
using namespace std;
#ifdef __GNUC__
namespace detail {
typedef double (&Yes)[1];
typedef double (&No)[2];
template< unsigned n >
Yes foo( char const (&)[n] );
No foo( ... );
} // namespace detail
#define CASSERT( e ) \
do { \
char a[1 + ((e)-(e))]; \
enum { isConstExpr = sizeof( detail::foo( a ) ) == sizeof( detail::Yes ) }; \
cout << "isConstExpr = " << boolalpha << !!isConstExpr << endl; \
(void)(isConstExpr? 1/!!(e) : (assert( e ), 0)); \
} while( false )
#else
namespace detail {
struct IsConstExpr
{
typedef double (&YesType)[1];
typedef double (&NoType)[2];
static YesType check( void const* );
static NoType check( ... );
};
} // namespace detail
#define CASSERT( e ) \
do { \
enum { isConstExpr = \
(sizeof( detail::IsConstExpr::check( e - e ) ) == \
sizeof( detail::IsConstExpr::YesType )) }; \
(void)(isConstExpr? 1/!!(e) : (assert( e ), 0)); \
} while( false )
#endif
int main()
{
#if defined( STATIC_TRUE )
enum { x = true };
CASSERT( x );
cout << "This should be displayed, OK." << endl;
#elif defined( STATIC_FALSE )
enum { x = false };
CASSERT( x );
cerr << "!This should not even have compiled." << endl;
#elif defined( DYNAMIC_TRUE )
bool x = true;
CASSERT( x );
cout << "This should be displayed, OK." << endl;
#elif defined( DYNAMIC_FALSE )
bool x = false;
CASSERT( x );
cout << "!Should already have asserted." << endl;
#else
#error "Hey, u must define a test case symbol."
#endif
}
Run Code Online (Sandbox Code Playgroud)
g ++问题的示例:
[D:\dev\test] > g++ foo.cpp -Werror=div-by-zero -D DYNAMIC_FALSE [D:\dev\test] > a isConstExpr = true !Should already have asserted. [D:\dev\test] > _
也就是说,g ++报告(甚至通过它的内在函数,甚至是创建VLA的wrt),它知道其值的非const变量是常量,但是它不能将该知识应用于整数除法,这样它就不会产生警告.
哎呀.
更新2:嗯,我是愚蠢的:当然宏可以添加一个普通的assert无论如何.由于OP只对可用时获取静态断言感兴趣,因此在某些极端情况下不适用于g ++.问题解决了,最初解决了.
| 归档时间: |
|
| 查看次数: |
4713 次 |
| 最近记录: |