首页 > 解决方案 > 使用 constexpr 作为 std::array 大小

问题描述

我有以下代码使用 aconstexpr作为数组大小。

#include <array>

template <size_t size>
constexpr size_t
GetSize(const char(&format)[size])
{
    // Iterate over format array and compute a value.
    size_t count = 0;
    for (size_t i = 0; i < size; ++i)
    {
        if (format[i] == '%')
        {
            ++count;
        }
    }

    return count;
}

template <size_t size>
constexpr auto
GetArray(const char(&format)[size])
{
    constexpr size_t arraySize = GetSize(format);
    return std::array<char, arraySize>();
}

int main(int argc, char** argv)
{
    static_assert(GetArray("hello").size() == 12, "failed");
}

但是,这无法在 VS2019 下编译,并出现以下错误

error C2131:  expression did not evaluate to a constant
message :  failure was caused by a read of a variable outside its lifetime
message :  see usage of 'format'
message :  see reference to function template instantiation 'auto GetArray<6>(const char (&)[6])' being compiled

这是编译器错误吗?如果是这样,是否有解决方法?

标签: c++visual-studio-2019

解决方案


constexpr 函数的问题在于,您可以使用 constexpr 参数和非 constexpr 参数调用 :

int constexpr f(int n)
{
    return ++n;
}

int constexpr n0 = 7;
int n1; std::cin >> n1;
f(n0); // result IS constexpr
f(n1); // result is NOT constexpr, just an ordinary int

由于这个特性,函数参数本身不能是 constexpr,或者更准确地说,不能在 constexpr 上下文中使用。所以在你的函数中:

constexpr size_t arraySize = getSize(format);
//                                      ^ cannot be used as constexpr, even if
//                                        constexpr has been passed to, so result
//                                        not either (the f(n1) case above)

您可以稍微修改第二个功能:

template <size_t Size>
constexpr auto
getArray()
{
    return std::array<char, Size>();
}

并像使用它一样

int main(int argc, char** argv)
{
    static_assert(getArray<getSize("hello")>().size() == 0, "failed");
    return 0;
}

当然,现在看起来很丑,但是你可能会躲在一个宏后面:

#define myGetArray(STRING) getArray<getSize(STRING)>()

或者干脆

#define getArray(STRING) std::array<char, getSize(STRING)>()

推荐阅读