它是合法的由constexpr抛出的异常使用的副作用?(Is it legal to use sid

2019-07-02 10:43发布

通常情况下,constexpr必须无副作用。 不过,我只是发现有可能在抛出的异常的构造函数使用的副作用。 该技术可被用于模拟为constexpr功能断言(),因为它是表现在下面的程序。

#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);
}

我用克++ 4.7.2和铛++ 3.1进行了测试。 当前提条件失败,你的错误定位和核心转储。

./constexpr_assert some_arg
assertion: <y != 0> failed (file: constexpr_assert.cpp, line: 26)
Aborted (core dumped)

因此,它的工作原理与目前的编译器,但它是合法的C ++ 11?

Answer 1:

它是合法的。

对于每个constexpr函数必须有导致的常量表达式(§7.1.5/ 5)一些参数值:

对于constexpr功能,如果存在,使得函数调用取代会产生一个常量表达式(5.19)无功能的参数值,该程序是非法的构造; 没有诊断需要。

请注意,这并不意味着每一个可能的参数值必须产生一个常量表达式。 divide显然具有导致常量表达式一些参数值: divide(1, 1)是一个简单的例子。 因此,这个定义显然是有效的。

但是,可以divide(1, 0)被称为? 是的,它可以。 有调用之间几乎没有差别constexpr函数或“正常”功能(§7.1.5/ 7):

到的呼叫constexpr函数产生相同的结果为等效的非呼叫constexpr不同之处在于所涉及的呼叫在所有方面功能constexpr函数可以在常量表达式出现。

请注意,调用constexpr功能可以在常量表达式出现,但没有从不会导致常量表达式禁止他们。 其目的是使一个可以调用constexpr与编译时和运行时参数(否则的有用功能constexpr将severaly限制)。

为了完整起见,让我们来看看是什么让一个常量表达式(§5.19/ 2):

一个条件表达式是一个核心常量表达式除非它涉及以下作为一个潜在的评价子表达式(§3.2)中的一个,但逻辑与(§5.14),逻辑OR(§5.15),和条件子表达式(§5.16)操作未评估未考虑[...]。

所以, divide(1, 1)是恒定的表达,但divide(1, 0)不是。 如果您使用的divide(1, 0)在一个模板参数,该程序将是病态的。 但除此之外,它的罚款。



文章来源: Is it legal to use side-effects in exceptions thrown by constexpr?