"如果constexpr()" Vs" if()"

时间:2017-04-16 06:39:31

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

if constexpr()if()之间的区别是什么?

我何时何地可以同时使用它们?

2 个答案:

答案 0 :(得分:17)

普通的if语句:

  • 每次控制到达时都会评估其状况,如果有的话
  • 确定要执行的两个子语句中的哪一个,跳过另一个
  • 无论在运行时实际选择哪个子语句,都要求两个子语句格式正确

if constexpr声明:

  • 在提供了所有必要的模板参数后,在编译时评估其条件
  • 确定要编译的两个子语句中的哪一个,丢弃另一个
  • 不要求丢弃的子语句格式正确

答案 1 :(得分:16)

唯一的区别是if constexpr在编译时被评估,而if则没有。这意味着在编译时可以拒绝分支,因此永远不会被编译。

想象一下,你有一个函数length,它返回一个数字的长度,或者一个具有.length()函数的类型的长度。你不能在一个函数中完成它,编译器会抱怨:

template<typename T>
auto length(const T& value) noexcept {
    if (std::integral<T>::value) { // is number
        return value;
    else
        return value.length();
}

int main() noexcept {
    int a = 5;
    std::string b = "foo";

    std::cout << length(a) << ' ' << length(b) << '\n'; // doesn't compile
}

错误讯息:

main.cpp: In instantiation of 'auto length(const T&) [with T = int]':
main.cpp:16:26:   required from here
main.cpp:9:16: error: request for member 'length' in 'val', which is of non-class type 'const int'
     return val.length();
            ~~~~^~~~~~

那是因为当编译器实例化length时,该函数将如下所示:

auto length(const int& value) noexcept {
    if (std::is_integral<int>::value) { // is number
        return value;
    else
        return value.length();
}

valueint,因此没有length成员函数,因此编译器会抱怨。编译器无法看到int永远不会达到该语句,但这并不重要,因为编译器无法保证这一点。

现在你可以专门化length,但对于很多类型(比如在这种情况下 - 每个数字和具有length成员函数的类),这会产生大量重复的代码。 SFINAE也是一个解决方案,但它需要多个函数定义,这使得代码比下面的代码需要更长的时间。

使用if constexpr代替if意味着分支(std::is_integral<T>::value)将在编译时进行评估,如果是true,那么每隔一个分支({{ 1}}和else if)被丢弃。如果是else,则检查下一个分支(此处为false),如果为else,则丢弃所有其他分支,依此类推......

true

现在,当编译器实例化template<typename T> auto length(const T& value) noexcept { if constexpr (std::integral<T>::value) { // is number return value; else return value.length(); } 时,它将如下所示:

length

所以这两个重载是有效的,代码将成功编译。