带有常量引用的 std::remove_const

2021-12-13 00:00:00 templates c++ c++11 std

为什么 std::remove_const 不将 const T& 转换为 T&?这个公认的相当人为的例子证明了我的问题:

Why does std::remove_const not convert const T& to T&? This admittedly rather contrived example demonstrates my question:

#include <type_traits>

int main()
{
    int a = 42;
    std::remove_const<const int&>::type b(a);

    // This assertion fails
    static_assert(
        !std::is_same<decltype(b), const int&>::value,
        "Why did remove_const not remove const?"
    );

    return 0;
}

上述情况很容易解决,因此对于上下文,请想象以下内容:

The above case is trivially easy to fix, so for context, imagine the following:

#include <iostream>

template <typename T>
struct Selector
{
    constexpr static const char* value = "default";
};

template <typename T>
struct Selector<T&>
{
    constexpr static const char* value = "reference";
};

template <typename T>
struct Selector<const T&>
{
    constexpr static const char* value = "constref";
};

int main()
{
    std::cout
        << Selector<typename std::remove_const<const int&>::type>::value
        << std::endl;

    return 0;
}

在上面的例子中,我希望显示 reference,而不是 constref.

In the above example, I'd expect reference to be shown, rather than constref.

推荐答案

std::remove_const 移除了顶级 const-qualifications.在 const T& 中,等同于 T const&,限定不是顶级的:实际上,它不适用于引用本身(即没有意义,因为根据定义,引用是不可变的),而是针对被引用的类型.

std::remove_const removes top level const-qualifications. In const T&, which is equivalent to T const&, the qualification is not top-level: in fact, it does not apply to the reference itself (that would be meaningless, because references are immutable by definition), but to the referenced type.

C++11 标准第 20.9.7.1 段表 52 规定,关于 std::remove_const:

Table 52 in Paragraph 20.9.7.1 of the C++11 Standard specifies, regarding std::remove_const:

成员 typedef 类型应命名为与 T 相同的类型,除了任何顶级常量限定符已被删除.[ 示例:remove_const::type 计算结果为volatile int,而 remove_const::type 计算const int*.― 结束示例 ]

The member typedef type shall name the same type as T except that any top-level const-qualifier has been removed. [ Example: remove_const<const volatile int>::type evaluates to volatile int, whereas remove_const<const int*>::type evaluates to const int*. ― end example ]

为了去掉const,你首先要应用std::remove_reference,然后应用std::remove_const,然后(如果需要)应用 std::add_lvalue_reference(或任何适合您的情况).

In order to strip const away, you first have to apply std::remove_reference, then apply std::remove_const, and then (if desired) apply std::add_lvalue_reference (or whatever is appropriate in your case).

注意:正如 Xeo 在评论中提到的,您可以考虑 使用别名模板,例如 Unqualified执行前两步,即去掉引用,然后去掉const-(和volatile-)限定.

NOTE: As Xeo mentions in the comment, you may consider using an alias template such as Unqualified to perform the first two steps, i.e. strip away the reference, then strip away the const- (and volatile-) qualification.

相关文章