【发布时间】:2012-10-13 21:20:31
【问题描述】:
通常,constexpr 必须没有副作用。但是,我刚刚发现可以在抛出异常的构造函数中使用副作用。该技术可用于模拟 constexpr 函数的 assert(),如下面的程序所示。
#include <iostream>
#include <cstdlib>
#include <stdexcept>
struct constexpr_precond_violated : std::logic_error
{
constexpr_precond_violated(const char* msg) :
std::logic_error(msg)
{
std::cerr << msg << '\n';
abort(); // to get a core dump
}
};
#define TO_STRING_IMPL(x) #x
#define TO_STRING(x) TO_STRING_IMPL(x)
#define CONSTEXPR_PRECOND(cond, value) \
((!(cond)) ? throw constexpr_precond_violated( \
"assertion: <" #cond "> failed (file: " \
__FILE__ ", line: " TO_STRING(__LINE__) ")") \
: (value))
constexpr int divide(int x, int y)
{
return CONSTEXPR_PRECOND(y != 0, x / y);
}
int main(int argc, char** argv)
{
// The compiler cannot know argc, so it must be evaluated at runtime.
// If argc is 2, the precondition is violated.
return divide(100, argc - 2);
}
我使用 g++ 4.7.2 和 clang++ 3.1 对其进行了测试。当先决条件失败时,您将获得错误位置和核心转储。
./constexpr_assert some_arg
assertion: <y != 0> failed (file: constexpr_assert.cpp, line: 26)
Aborted (core dumped)
所以它适用于当前的编译器,但它是合法的 C++11 吗?
【问题讨论】:
-
出于兴趣,如果您将编译时常量
0作为第二个参数提供给divide(),会发生什么? 编译器是否“抛出异常”? :) -
static_assert(divide(1, 0) >= 0, "testing");根本不会编译 return divide(1, 0);使用 Clang 编译并且仅在运行时失败。
-
您必须小心区分常量表达式和
constexpr函数。像“constexpr必须没有副作用”这样的东西是不精确的。将constexpr视为一个关键字(想到static)。 -
您可以在
&&、||或?:的子表达式上使用在编译时不计算的表达式。异常的构造函数没有什么特别之处。
标签: c++ c++11 assert language-lawyer constexpr