繁体   English   中英

无法在C ++中使std :: array成为constexpr

[英]Cannot make std::array a constexpr in C++

我在以下代码中收到VS2017的``错误C3615:constexpr函数'to_array'无法导致常量表达式''的编译器错误:

#include <stdio.h>
#include <array>

template <typename T>
static constexpr std::array<std::uint8_t, sizeof(T)> to_array(T value)
{
    std::array<std::uint8_t, sizeof(T)> result {};

    for (std::size_t i{ sizeof(T) }; i != 0 ; --i)
    {
        result[i - 1] = static_cast<uint8_t>(value >> ((sizeof(T) - i) * 8));
    }

    return result;
}

int main()
{
    constexpr uint64_t sample = UINT64_C(0xab28ecb46814fe75);

    //error C3615: constexpr function 'to_array' cannot result in a constant expression
    constexpr auto a = to_array(sample);

    return 0;
}

如果理论上std :: array可以是constexpr ,为什么我在这里得到错误?

EDIT1:

它编译时没有循环:

template <typename T>
static constexpr std::array<std::uint8_t, sizeof(T)> to_array(T value)
{
    std::array<std::uint8_t, sizeof(T)> result {};

    //this is OK
    return result;
}

EDIT2:

循环的完整错误消息是:

error C3615: constexpr function 'to_array' cannot result in a constant expression
note: failure was caused by an uninitialized variable declaration
note: see usage of 'result'

如果理论上std :: array可以是constexpr ,为什么我在这里得到错误?

您所提供的链接处理构建 std::array的一部分constexpr ,没有做别的吧,像你一样。

它编译没有循环

您的错误与循环本身无关,因为它与在constexpr函数体内的std::array operator[]直接使用有关。

自C ++ 17以来std::array operator[] constexpr ,但似乎MSVC 19尚未实现它,即使它在规范中。 因此,在您的情况下,启用C ++ 17(编译器标志/std:c++latest )进行构建将无法直接解决问题:-(

好消息是MSVC 20符合标准 :-)

完整的错误消息是:

error C2131: expression did not evaluate to a constant
note: failure was caused by call of undefined function or one not declared 'constexpr'
note: see usage of 'std::array<uint8_t,8>::operator []'
note: while evaluating 'to_array(12333367839138578037)'
fatal error C1903: unable to recover from previous error(s); stopping compilation

现在,如果我们看一下operator[]的声明,我们会发现在该版本的Microsoft STD实现中它还不是constexpr

reference operator[](_In_range_(0, _Size - 1) size_type _Pos)

解决方法是使用C数组,然后将其转换为std::array

template<std::size_t... is, std::size_t n = sizeof...(is)>
constexpr std::array<std::uint8_t, n>
    to_array(std::uint8_t (&arr)[n], std::index_sequence<is...>)
{
    return {arr[is]...};
}

template <typename T>
constexpr std::array<std::uint8_t, sizeof(T)> to_array(T value)
{
    std::uint8_t result[sizeof(T)];
    ...
    return to_array(result, std::make_index_sequence<sizeof(T)>{});
}

要么

template<typename T, std::size_t... is>
constexpr std::array<std::uint8_t, sizeof(T)> 
    to_array(T value, std::index_sequence<is...>)
{
    return {static_cast<std::uint8_t>(value >> ((sizeof(T) - is - 1) * 8))...};
}

template <typename T>
constexpr std::array<std::uint8_t, sizeof(T)> to_array(T value)
{
    return to_array(value, std::make_index_sequence<sizeof(T)>{});
}

但是无论如何,您不能在constexpr上下文中对结果使用operator[]

我今天遇到了这个问题。 我决定尝试包装std :: array以查看是否可以添加constexpr支持。 我才刚开始,并且在我使[]运算符重载之前,这种方法确实起作用了。

template <typename T, unsigned S> struct _array : public std::array<T,S> {};

现在可以使用_array代替std :: array。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM