首页 > 解决方案 > 可在 static_assert 中使用的非 constexpr 对象

问题描述

我会举个例子

#include <array>

// Just in case std::array has superpowers...
template <typename T, unsigned n>
struct dummy {
    constexpr unsigned size() const noexcept {
        return n;
    }

    unsigned badsize() const noexcept {
        return n;
    }
};

void fun()
{
    std::array<int, 8> arr{};
    static_assert(arr.size() == 8); // OK

    dummy<int, 8> arr2{};
    static_assert(arr2.size() == 8); // OK
    static_assert(arr2.badsize() == 8); // Compiler Error
}

问题是:

允许非 const(expr)变量arr并将arr2非静态但 constexpr成员函数size()作为常量表达式(尤其是 bool-constexpr)评估的语言机制/规则是什么?

我现在花了一些时间搜索 SO 和 cppreference.com,但无法弄清楚为什么允许这样做。

从旧版本的 GCC 升级时,我最近不得不更新类似的代码static_assert(std::tuple_size_v<decltype(arr)> == 8),所以我最初认为它可能只是一些 GCC 扩展。但是我现在已经让这种代码再次开始使用新版本的 GCC,我想了解这里发生了什么。

标签: c++

解决方案


确实没有任何充分的理由允许这样做:只是在常量表达式的规则中不考虑将(非 constexpr)局部变量的地址作为this成员函数传递。它甚至被允许在被调用的函数中使用,但你不能使用类的任何(非静态)成员变量,除非它们真的被初始化为常量。当然,这些 size 函数不需要这样做,即使它们实际上不是staticthis

真正令人困惑的是,这个权限并没有扩展到引用:使用它们被认为是读取有效指针值,并且它必须单独是一个常量。有一些积极的提议允许在使用这种“未知对象”的成员变量的同样不可避免的限制下进行这种使用。


推荐阅读