我需要在else-if后面加上constexpr吗?

79

这个答案的启发,我尝试复制并粘贴(并在main()中添加测试)此代码:

template<typename T>
std::tuple<int, double> foo(T a) {
    if constexpr (std::is_same_v<int, T>)
        return {a, 0.0};
    else if (std::is_same_v<double, T>)
        return {0, a};
    else
        return {0, 0.0};
}

int main() {
    auto [x, y] = foo("");
    std::cout << x << " " << y;
}

这很简单 - 如果T被推断为int,则我们想返回一个元组[a, 0.0]。如果T被推断为double,则我们想返回一个元组[0, a]。否则,我们想返回[0, 0.0]
如您所见,在main()函数中,我使用const char*参数调用foo,这应该导致xy0。但事实并非如此。
在尝试编译它时,我遇到了一个奇怪的错误:

error: could not convert '{0, a}' from '<brace-enclosed initializer list>' to 'std::tuple<int, double>'

我当时就像“什么?”。我为什么要那样做...我明确使用了std::is_same来启用return {0, a},只有当a的类型被推断为double时才会出现。
所以我赶紧跑到cppreference上看if-constexpr。在页面底部,在Notes上面,我们可以看到这段代码:
extern int x; // no definition of x required
int f() {
if constexpr (true)
    return 0;
else if (x)
    return x;
else
    return -x;
}

我想了一下,嗯...?我真的看不出原始代码有什么问题。它们使用相同的语法和语义...

但我很好奇。我想知道是否可能通过某些奇怪(当时)的方式来解决这个问题,所以我将原始代码更改为:

template<typename T>
std::tuple<int, double> foo(T a) {
    if constexpr (std::is_same_v<int, T>)
        return {a, 0.0};
    else if constexpr (std::is_same_v<double, T>) // notice the additional constexpr here
        return {0, a};
    else
        return {0, 0.0};
}

int main() {
    auto [x, y] = foo("");
    std::cout << x << " " << y;
}

完成了!代码编译并按预期执行。那么,我的问题是 - 在这种情况下,我们是否需要在if-else语句中的每个if语句后面加上constexpr还是只有我的编译器需要?我正在使用GCC 7.3。

1个回答

105

在这种情况下,我们需要在if-else块中的每个if语句后面加上constexpr吗?

是的。else-if块1其实是个谎言:),只有if块1和else块1。这是编译器看到你的代码的方式:

if constexpr (std::is_same_v<int, T>)
    return {a, 0.0};
else // {
    if (std::is_same_v<double, T>)
        return {0, a};
    else
        return {0, 0.0};
// }

else if (/*...*/)只是人们普遍使用的格式约定。因此,您可以清楚地看到第二个constexpr是必需的。


1:“块”不是正确的术语。if是一个语句(带有可选的else部分)。一个块是{ /*...*/ }


8
请注意,cppref的示例是正确的,缺少constexpr是有意为之的,以显示您不必具有x的定义,因为else块(请参见答案)会被丢弃。 - Rakete1111
1
@MarekR 内部的 if 语句仍需标记为 constexpr。即使 fooconstexpr,函数内部的所有内容也不一定都是 constexpr 的(因为你仍然可以在运行时调用该函数)。 - Rakete1111
1
原始示例中没有代码块({}),除了必需的函数定义块之外。我建议使用“语句”这个标准术语描述。 - Arne Vogel
1
@ArneVogel 是的,我只是使用了与 OP 相同的术语。我会更改。 - Rakete1111
2
else 不是一个完整的语句,它只是其中的一部分。 - T.C.
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接