即使在初始化中仅调用 constexpr 函数,数组常量也不会评估为常量

Array constant not evaluating to constant even though only constexpr functions called in initialization

这是我的代码的简化、可重现版本:

type_id.h

template<typename>
void type_id() {}

typedef void(*type_id_t)();

c_sort.h(基于this answer

template<typename Array>
constexpr void c_sort_impl(Array& array_) noexcept {
    using size_type = typename Array::size_type;
    size_type gap = array_.size();
    bool swapped = false;
    while ((gap > size_type{ 1 }) or swapped) {
        if (gap > size_type{ 1 }) {
            gap = static_cast<size_type> (gap / 1.247330950103979);
        }
        swapped = false;
        for (size_type i = size_type{ 0 }; gap + i < static_cast<size_type> (array_.size()); ++i) {
            if (array_[i] > array_[i + gap]) {
                auto swap = array_[i];
                array_[i] = array_[i + gap];
                array_[i + gap] = swap;
                swapped = true;
            }
        }
    }
}

template<typename Array>
constexpr Array c_sort(Array array_) noexcept {
    auto sorted = array_;
    c_sort_impl(sorted);
    return sorted;
}

foo.h

#include "type_id.h"
#include "c_sort.h"
#include <array>

template<class... Cs>
struct Foo
{
    constexpr static auto key =
        c_sort( std::array<type_id_t, sizeof...(Cs)>{ type_id<Cs>... } );
};

如果我尝试实例化 Foo,我会收到编译器错误提示 expression did not evaluate to a constant。为什么是这样?在初始化key时,我只调用标有constexpr的函数。表达式的哪一部分不能在编译时求值?

最新版本的 GCC 或 Clang 会告诉您未能生成常量表达式的计算。参见 https://godbolt.org/z/adhafn8v7

问题是比较:

array_[i] > array_[i + gap]

不相等的函数指针之间的比较(除了检查它们是否相等)有一个未指定的结果,因此不允许在常量表达式求值中。