有没有可能知道何时constexpr真的是一个constexpr?
由于constexpr的扩展版本(我认为是C ++ 14),你可以声明constexpr函数,它可以用作“真正的”constexpr,也就是说,代码可以在编译时执行,或者可以表现为内联函数。 所以什么时候可以有这个程序:
#include <iostream>
constexpr int foo(const int s) {
return s + 4;
}
int main()
{
std::cout << foo(3) << std::endl;
const int bar = 3;
std::cout << foo(bar) << std::endl;
constexpr int a = 3;
std::cout << foo(a) << std::endl;
return 0;
}
当然,结果是:
7
7
7
到现在为止还挺好。 所以我的问题是:如果函数在编译时或运行时执行,有没有一种方法(可能是标准的)知道foo(const int s)?
编辑:也有可能在运行时知道在编译时是否评估函数?
列出的技术是可行的,但由于它使用static_assert
所以它不是友好的。 一个更好的方法(理论上你会明白我的意思)来检查函数是否为noexcept
。 为什么? 因为常量表达式总是不被接受,即使函数没有被标记为这样。 所以,请考虑以下代码:
template <class T>
constexpr void test_helper(T&& t) {}
#define IS_CONSTEXPR(...) noexcept(test_helper(__VA_ARGS__))
test_helper
是constexpr
,所以只要它的参数是一个常量表达式。 如果它是一个常量表达式,它将是noexcept
,否则它不会是(因为它没有被标记为这样)。
现在让我们来定义这个:
double bar(double x) { return x; }
constexpr double foo(double x, bool b) {
if (b) return x;
else return bar(x);
}
如果x
是一个常量表达式,则foo
只有noexcept
,而b
是true; 如果布尔值为假,那么我们称之为非constexpr
函数,破坏我们的constexpr- ness。 所以,我们来测试一下:
double d = 0.0;
constexpr auto x = IS_CONSTEXPR(foo(3.0, true));
constexpr auto y = IS_CONSTEXPR(foo(3.0, false));
constexpr auto z = IS_CONSTEXPR(foo(d, true));
std::cerr << x << y << z;
它编译,太棒了! 例如,这给了我们编译时布尔(不编译失败),可以用于sfinae。
赶上? 那么,铿有一个多年的错误,并没有正确处理。 但是,海湾合作委员会呢。 现场示例:http://coliru.stacked-crooked.com/a/e7b037932c358149。 它打印“100”,因为它应该。
我认为执行该操作的规范方法是使用static_assert
。 static_assert
在编译时被评估,所以如果它们的条件为false,它们将破坏构建。
#include <iostream>
constexpr int foo(const int s) {
return s + 4;
}
int main()
{
std::cout << foo(3) << std::endl;
const int bar = 3;
std::cout << foo(bar) << std::endl;
constexpr int a = 3;
std::cout << foo(a) << std::endl;
static_assert(foo(3) == 7, "Literal failed");
static_assert(foo(bar) == 7, "const int failed");
static_assert(foo(a) == 7, "constexpr int failed");
return 0;
}
clang++ -std=c++14 so1.cpp
适合我编译,显示一切正常。
在一个constexpr
函数中,你不能判断你是否正在一个constexpr
上下文中进行评估。 已经有许多建议来添加这个功能。 没有成功。
在constexpr
函数外部,有很多方法可以确定是否在constexpr
上下文中调用具有特定参数集的函数。 最简单的方法是在需要constexpr
的上下文中使用结果。
假设你的constexpr表达式返回一个非空的整数或指针类型(包括函数指针):
#define CONSTEXPR_EVAL(...)
std::integral_constant<
std::decay_t<decltype(__VA_ARGS__)>,
__VA_ARGS__
>::value
那么如果在编译时不能计算bar(foo, true)
,并且如果可以在编译时计算它,它将返回该值CONSTEXPR_EVAL( bar(foo, true) )
那么CONSTEXPR_EVAL( bar(foo, true) )
将无法编译。
涉及noexcept
其他技巧(在编译时评估的函数是noexcept
)可以工作(请参阅@NirFriedman的答案)。
上一篇: Is it possible to know when is constexpr really a constexpr?