【问题标题】:Do I need to put constexpr after else-if?我需要把 constexpr 放在 else-if 之后吗?
【发布时间】:2019-02-20 16:55:47
【问题描述】:

this answer 的启发,我尝试复制并粘贴(并在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,这应该导致xy 成为0情况并非如此

在尝试编译时,我遇到了一个奇怪的错误:

错误:无法将“{0, a}”从“&lt;brace-enclosed initializer list&gt;”转换为“std::tuple&lt;int, double&gt;

而我就像什么?。我到底为什么要那样...我专门使用std::is_same 来启用return {0, a} a 的类型被推断为double

所以我在 if-constexpr 上迅速跑到 cppreference。在页面底部,Notes上方,我们可以看到这段sn-p的代码:

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。

【问题讨论】:

    标签: c++ if-statement c++17 if-constexpr


    【解决方案1】:

    在这种情况下,我们是否需要在 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 部分)。一个块是{ /*...*/ }

    【讨论】:

    • @Fureeish 另请注意,cppref 的示例是正确的,缺少的 constexpr 是设计用来表明您不必定义 x 因为 else 块(见答案) 被丢弃。
    • @MarekR 内部if 仍然需要装饰。仅仅因为 fooconstexpr 并不意味着函数内的所有内容都是 constexpr(因为您仍然可以在运行时调用该函数)。
    • 在原始示例中没有块 ({}),但函数定义所需的块除外。我建议按照标准术语说“声明”。
    • @ArneVogel 是的,我只是使用了与 OP 相同的术语。会改变
    • else 甚至不是一个声明。这是一个的一半。
    猜你喜欢
    • 2019-05-18
    • 2016-01-28
    • 1970-01-01
    • 2011-03-27
    • 2017-05-25
    • 1970-01-01
    • 1970-01-01
    • 2015-03-13
    相关资源
    最近更新 更多