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

时间:2017-02-02 07:29:17

标签: c++ c++11 const

#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 个答案:

答案 0 :(得分: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推断出来(强调我的):

      

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

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

      

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

    两者均指工作草案。

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