首页 文章

为什么std :: is_const :: value 'false'即使T的value_type是const?

提问于
浏览
24
#include <type_traits>

struct foo;
int main()
{
    const foo *bar;

    static_assert(std::is_const<decltype(*bar)>::value,
                  "expected const but this is non-const!");
}

这会导致意外失败 static_assert . 这有点类似于const引用上的this question但不完全相同 .

在我的情况下,取消引用 bar 应该给出一个 const foo 的实例作为其类型,但 std::is_const 却说不然 .

1 回答

  • 35

    不久之后,因为引用或指向const类型的指针不是const类型 .
    请注意 decltype(*bar) 不是 const foo ,它是 const foo & 并且它们实际上是不同的野兽 .


    考虑给出here的示例:

    std::cout << std::is_const<const int *>::value << '\n'; // false
    std::cout << std::is_const<int * const>::value << '\n'; // true
    

    我们看到 std::is_const<const int *>::value 是假的, std::is_const<int * const>::value 是真的 .
    那是因为在 const int * 中,类型是指向const的指针,这不是 is_const (实际上是标准)所预期的const类型 . 在 int * const 中,const限定符适用于指针类型,而不适用于指向的类型,因此类型是常量类型,无论它指向什么 .
    类似的东西适用于 const foo & ,这是对const的引用 .

    您可以使用此解决方案:

    static_assert(std::is_const<std::remove_reference_t<decltype(*bar)>>::value, "expected const but this is non-const!");
    

    或者甚至是这样,因为你实际上不需要做 *bar

    static_assert(std::is_const<std::remove_pointer_t<decltype(bar)>>::value, "expected const but this is non-const!");
    

    在这种情况下,通过使用 remove_pointer_t / remove_reference_t 删除指针/引用,您的类型变为 const foo ,这实际上是一个const类型 .


    作为旁注,上面的示例使用C 14-ish std::remove_reference_tstd::remove_pointer_t 类型特征 .
    您可以轻松地将这些代码行转换为C 11,如下所示:

    static_assert(std::is_const<typename std::remove_pointer<decltype(bar)>:: type>::value, "expected const but this is non-const!");
    

    值得一提的是给答案的一些评论,以提供更多细节:

    • 感谢@DanielFischer提出的问题:

    有没有简短的解释为什么decltype(* bar)是const foo而不是const foo?

    我不是语言律师,但我想这可以从[expr.unary.op]/1(强调我的)推断出来:

    一元*运算符执行间接:它所应用的表达式应该是指向对象类型的指针,或指向函数类型的指针,结果是一个引用表达式指向的对象或函数的左值 .

    并且[dcl.type.simple]/4.4(强调我的):

    否则,如果e是左值,则decltype(e)是T&,其中T是e的类型;

    两者都提到了工作草案 .

    • 感谢@LightnessRacesInOrbit的评论 . 注意 decltype(*bar)const foo &decltype 的一个有趣的C怪癖,因为 *bar 不是 const foo & .

相关问题