if-else 后缺少 return 语句

Missing return statement after if-else

一些编译器(Intel icc,pgi/nvc++)对下面的函数发出“缺少 return 语句”警告,而其他编译器(gcc,clang)即使使用 -Wall -Wextra -pedantic:

根据标准,下面的代码是否合法?

这是我的代码中发出警告的最小可重现示例。将其简化为仅一个函数即可删除警告。

// test.cpp
#include <climits>
#include <cstddef>

template<class T, std::size_t N>
class Test
{
public:

    class Inner;

private:
    static constexpr std::size_t NB_ = sizeof(std::size_t) * CHAR_BIT;
    static constexpr std::size_t NI_ = (N + NB_ - 1) / NB_;
};

template<class T, std::size_t N>
class Test<T, N>::Inner
{
public:

    Inner() : b_{0}, j_{0} {}

    friend bool operator!= (Inner x, Inner y)
    {
        if constexpr(J_ > 0)
            return x.j_ != y.j_ || x.b_ != y.b_;
        else
            return x.b_ != y.b_;
    }

private:
    static constexpr std::size_t J_ = NI_ - 1;
    std::size_t b_;
    std::size_t j_;
};

int main()
{
    Test<int, 50>::Inner x, y;
    int a, b;
    x.b_ = a; y.b_ = b;
    x != y;
}

编译:

> nvc++ test.cpp -std=c++17
"test.cpp", line 30: warning: missing return statement at end of non-void function "operator!="
      }
      ^
          detected during instantiation of class "Test<T, N>::Inner [with T=int, N=50UL]" at line 41

能否将这些项目设置为编译为早期的 C++ 标准?

一些较旧的编译器不喜欢代码块中间的 returns(还有一些编译器不喜欢代码块开头以外的任何地方的变量标识符)。

对于那些抱怨的人,我只是编码为:

ret_type f(...)
{
    ret_type result = DEFAULT_VALUE; //default value defined elsewhere
    if (condition)
        result = value_1; //presumed valid ret_type value
    else
        result = value_2; //presumed valid ret_type value
    
    return result;
}

C++ 标准是这样说的,参见 [stmt.return]/2:

Flowing off the end of a constructor, a destructor, or a function with a cv void return type is equivalent to a return with no operand. Otherwise, flowing off the end of a function other than main results in undefined behavior.

您的 operator != 正是这样做的。它永远不会流出函数的末尾,因为所有控制路径都以 return.

结尾

因此代码是正确的,编译器的诊断是错误的。

我有一些功能,其中只有特定的结果是可接受的,以便 return,您的设置是怎样的。如果它确实是一个小众案例,其中两个 if 语句都是错误的(强调小众),那么就会有问题并且可以抛出异常。

在我的例子中,在最后一个 if 子句之后,我添加:

throw std::invalid_argument("\nx  and y cannot be compared\n)");

要让您的代码在没有警告的情况下进行编译 (Intel ICC 2021.3.0),请使用 __builtin_unreachable() 告诉编译器控制流永远不会结束:

friend bool operator!= (Inner x, Inner y)
{
    if constexpr(J_ > 0)
        return x.j_ != y.j_ || x.b_ != y.b_;
    else
        return x.b_ != y.b_;
    __builtin_unreachable();
}