我正在尝试编写以下形式的constexpr
函数:
constexpr int foo(bool cond) {
int a, b, c;
if (cond) {
a = 1;
b = 2;
c = 3;
}
else {
a = -1;
b = -2;
c = -3;
}
return a + b + c;
}
然而,编译器抱怨我正在使用未初始化的变量,尽管事实上保证了局部变量的最终初始化。
我可以重新编写函数来使用三元运算符,即int a = cond ? 1 : -1;
等,但我不愿意。有没有办法说服编译器初始化局部变量?
答案 0 :(得分:31)
然而,编译器抱怨我使用的是未初始化的变量,尽管事实上保证了局部变量的最终初始化。
初始化或初始化,没有"最终初始化。"而且,对于constexpr
函数,需要在[dcl.constexpr]:
constexpr
函数的定义应满足以下要求:[...] function-body 应为= delete
,= default
或复合语句,它不包含非文字类型或静态或线程存储持续时间的变量的定义,或者,其中没有 初始化已执行。
constexpr
个函数中没有未初始化的变量,a
,b
和c
适合您。
那你能做什么?您可以对a
,b
和c
进行零初始化。这绕过了这个要求。或者,您可以在a
中的每个范围内初始化b
,c
和if
。或者您可以按照另一个constexpr
函数进行求和:
constexpr int f(int a, int b, int c) { return a+b+c; };
constexpr int foo(bool cond) {
if (cond) {
return f(1,2,3);
}
else {
return f(-1,-2,-3);
}
}
有很多方法可以解决这个问题。
答案 1 :(得分:13)
然而,编译器抱怨我使用的是未初始化的变量,尽管事实上保证了局部变量的最终初始化。
该标准要求初始化constexpr
函数中的所有局部变量。
来自§7.1.5, par. 3 ([dcl.constexpr]):
constexpr
函数的定义应满足以下要求: [...]其函数体应为
= delete
,= default
或不包含 [...]的复合语句非文字类型或静态或线程存储持续时间的变量的定义,或者不执行初始化的定义。 [...]
constexpr int uninit() { int a; // error: variable is uninitialized return a; }
在C ++ 17中,您可以使用std::tuple
,structured bindings和IIFE (immediately-invoked function expression)来保留原始结构:
constexpr int foo(bool cond)
{
const auto [a, b, c] = [&cond]
{
if (cond)
{
return std::tuple(1, 2, 3);
}
else
{
return std::tuple(-1, -2, -3);
}
}();
return a + b + c;
}
由于您的条件和分支是微不足道的,三元运算符就足够了。如果将来您的初始化逻辑变得更复杂,上面的代码片段可能会对您有所帮助,但下面的代码片段应该足够好了:
constexpr int foo(bool cond)
{
const auto [a, b, c] = cond ? std::tuple(1, 2, 3)
: std::tuple(-1, -2, -3);
return a + b + c;
}
在C ++ 14中,您可以使用std::make_tuple
和std::get
代替:
constexpr int foo(bool cond)
{
const auto abc = cond ? std::make_tuple(1, 2, 3)
: std::make_tuple(-1, -2, -3);
return std::get<0>(abc) + std::get<1>(abc) + std::get<2>(abc);
}
在C ++ 11中,您可以将函数拆分为两个较小的函数:
template <typename TTuple>
constexpr int sum3(const TTuple& abc)
{
return std::get<0>(abc) + std::get<1>(abc) + std::get<2>(abc);
}
constexpr int foo(bool cond)
{
return cond ? sum3(std::make_tuple(1, 2, 3))
: sum3(std::make_tuple(-1, -2, -3));
}
如果你决定走这条路,那么Barry's solution肯定会更好。
以上所有解决方案:
制作a
,b
,c
变量const
,这总是一件好事。
仅对cond
执行一次检查,以便与OP中的代码结构非常相似。
答案 2 :(得分:1)
@Borgleader方式就足够了:
constexpr int foo(bool cond) {
int a=0, b=0, c=0;
if (cond) {
a = 1;
b = 2;
c = 3;
}
else {
a = -1;
b = -2;
c = -3;
}
return a + b + c;
}
在C ++ 11中编译时没有错误,并且只警告constexpr函数中的变量声明是C ++ 14扩展并且在C ++ 14模式下没有警告(使用CLang 3.4。 1)
这是干净的,易于阅读和编写,并且接近原始代码。但毫无疑问,@Barry's solution更好。