为什么 std::extent 不能处理对像运算符 sizeof 这样的数组的引用?

Mae*_*tro 6 c++ arrays extent

如果我想获取我可以使用的数组的大小(元素数),sizeof(a) / sizeof(a[0])但新标准可以使用类型特征来做到这一点:

int main(){

    int a[]{5, 7, 2, 3, 6, 7};

    std::cout << std::extent<decltype(a)>::value << '\n'; // 6

    auto& refA = a;
    std::cout << std::extent<decltype(refA)>::value << '\n'; // 0
    std::cout << sizeof(refA) / sizeof(refA[0]) << '\n'; // 6
    std::cout << std::extent<std::remove_reference<decltype(refA)>::type>::value << '\n'; // 6
 
    std::cout << "\ndone!\n";
}
Run Code Online (Sandbox Code Playgroud)

一切正常,但为什么不能std::extentsizeof()运算符那样处理对数组的引用?我必须删除上一个示例中的引用才能获得实际的数组类型。

moi*_*rex 0

原因在于执行和标准背后的诚实;看看 GCC 的实现:

  /// extent
  template<typename, unsigned _Uint>
    struct extent
    : public integral_constant<std::size_t, 0> { };

  template<typename _Tp, unsigned _Uint, std::size_t _Size>
    struct extent<_Tp[_Size], _Uint>
    : public integral_constant<std::size_t,
                   _Uint == 0 ? _Size : extent<_Tp,
                               _Uint - 1>::value>
    { };

  template<typename _Tp, unsigned _Uint>
    struct extent<_Tp[], _Uint>
    : public integral_constant<std::size_t,
                   _Uint == 0 ? 0 : extent<_Tp,
                               _Uint - 1>::value>
    { };
Run Code Online (Sandbox Code Playgroud)

甚至cppreference中指定的可能实现:

template<class T, unsigned N = 0>
struct extent : std::integral_constant<std::size_t, 0> {};
 
template<class T>
struct extent<T[], 0> : std::integral_constant<std::size_t, 0> {};
 
template<class T, unsigned N>
struct extent<T[], N> : std::extent<T, N-1> {};
 
template<class T, std::size_t I>
struct extent<T[I], 0> : std::integral_constant<std::size_t, I> {};
 
template<class T, std::size_t I, unsigned N>
struct extent<T[I], N> : std::extent<T, N-1> {};
Run Code Online (Sandbox Code Playgroud)

T[]与数组的引用不同;所以它会退回到默认的,即:

    template<class T, unsigned N = 0>
    struct extent : std::integral_constant<std::size_t, 0> {};
Run Code Online (Sandbox Code Playgroud)

始终为 0。

也可以对其进行自定义以支持引用,但是您可能希望它支持constvolatile以及const volatile实现者(如果是我)像这样制作的其他内容(来自我的 web++ 项目):

        WEBPP_REMOVE_CVREF()
        WEBPP_REMOVE_CVREF(const)
        WEBPP_REMOVE_CVREF(volatile)
        WEBPP_REMOVE_CVREF(const volatile)
        WEBPP_REMOVE_CVREF(&)
        WEBPP_REMOVE_CVREF(&&)
        WEBPP_REMOVE_CVREF(const&)
        WEBPP_REMOVE_CVREF(const&&)
        WEBPP_REMOVE_CVREF(volatile&)
        WEBPP_REMOVE_CVREF(volatile&&)
        WEBPP_REMOVE_CVREF(const volatile&)
        WEBPP_REMOVE_CVREF(const volatile&&)
Run Code Online (Sandbox Code Playgroud)

是的,这样做不太漂亮,对吗?因此,实际上将其交给用户而不是库实现者或标准会更方便,通常也不会那么混乱。

  • 为什么要发布带有文字的图片?请不要发布屏幕截图 - 请以文本形式发布文本。 (2认同)