首页 > 解决方案 > constexpr 函数中的 For 循环无法使用 MSVC 19.23 编译

问题描述

以下代码在 Clang 和 GCC 中编译,但在 MSVC 中失败。

template <typename... FieldsSequence>
struct S {
    static constexpr bool checkIdUniqueness()
    {
        using IdType = int;
        constexpr IdType fieldIds[sizeof...(FieldsSequence)]{ 0 };
        for (size_t i = 0; i < std::size(fieldIds) - 1; ++i)
        {
            if (fieldIds[i] > fieldIds[i + 1])
            {
                constexpr auto tmp = fieldIds[i];
                fieldIds[i] = fieldIds[i + 1];
                fieldIds[i + 1] = tmp;
            }
        }

        return true;
    }
};

错误信息是:

expression did not evaluate to a constant
note: failure was caused by a read of a variable outside its lifetime
note: see usage of 'i'

有没有办法让这三个编译器都工作?最终,我需要对数组进行冒泡排序,以在编译时断言所有值都是唯一的。

https://godbolt.org/z/9XbP6-

标签: c++for-loopc++17constexprcompile-time

解决方案


你过度使用了constexpr声明。一方面,如果fieldIds声明了,constexpr那么它也是常量,你不能改变它。至于tmp,因为它声明constexpr了初始化程序必须是一个常量表达式,但它不能是一个真正的表达式。

正确的方法是constexpr从这些声明中删除:

template <typename... FieldsSequence>
struct S {
    static constexpr bool checkIdUniqueness()
    {
        using IdType = int;
        IdType fieldIds[sizeof...(FieldsSequence)]{ 0 };
        for (size_t i = 0; i < std::size(fieldIds) - 1; ++i)
        {
            if (fieldIds[i] > fieldIds[i + 1])
            {
                auto tmp = fieldIds[i];
                fieldIds[i] = fieldIds[i + 1];
                fieldIds[i + 1] = tmp;
            }
        }

        return true;
    }
};

函数作为一个整体仍然可以在常量表达式中求值,但是现在对这些变量没有额外的要求会干扰它们的声明或使用。


推荐阅读