使用constexpr作为std :: array的大小

时间:2019-10-17 03:34:44

标签: c++ visual-studio-2019

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

#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

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

3 个答案:

答案 0 :(得分:1)

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)>()

答案 1 :(得分:0)

我不知道您是否绝对需要GetSize()函数用于其他用途,但是在您的GetArray中,您已经可以访问数组的长度,因此您可以执行以下操作:

#include <array>

template <std::size_t N>
constexpr auto
GetArray(const char(&format)[N])
{
    return std::array<char, N*2>{};
}

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

答案 2 :(得分:0)

这是C ++ 17工作解决方案,使用lambda将char数组包装为constexpr。

return $this->hasMany('api-inquery\App\Inquery', 'barcode', 'barcode_valet');

compile-time-string-parsing改编而成,您可以阅读以获取更多信息