为什么在此模板结构中丢失了const

Why is const lost in this template structure?

本文关键字:const 结构 为什么      更新时间:2023-10-16

已知以下功能指针具有不同的类型:

void foo_int_ref(int&);
void foo_const_int_ref(const int&);
static_assert(
    !std::is_same<
        decltype(foo_int_ref),
        decltype(foo_const_int_ref)
    >::value,
    "Types should be different");

让我们考虑以下概括:

template<typename T>
void foo(T t) {}
template<typename T>
struct ref_vs_const_ref {
    typedef decltype(foo<T>) foo_T;
    typedef decltype(foo<const T>) foo_const_T;
};
using int_ref_vs_const_ref = ref_vs_const_ref<int&>;
static_assert(
    !std::is_same<
        typename int_ref_vs_const_ref::foo_T,
        typename int_ref_vs_const_ref::foo_const_T
    >::value,
    "Types should be different"); // -- it fails

最后一个断言失败了。由于某种原因,const丢失了foo_const_T。但是为什么?

值参数上的const 以任何形状或形式影响签名。当您从非网板声明中删除参考时,也是如此。const仅影响函数定义中参数的使用。如果添加了引用或指针的类型事物变化,并且const会影响函数的类型。

在您的嵌套类型中,T是应用constint&。但是,T&T& const也是相同的类型。我想您的混乱源于您对左侧的const的不明智的放置:它更多是const适用于顶级实体。

已经给出了"为什么"的答案。这是解决问题的可能方法 - 将" const"添加到嵌套类型:

template<typename T, typename = void>
struct add_value_const
{
    using type = const T;
};
template<typename T>
using add_value_const_t = typename add_value_const<T>::type;
template<typename T>
struct add_value_const<
    T, std::enable_if_t<
        std::is_reference<T>::value
    >
>
{
    using type = std::conditional_t<
        std::is_lvalue_reference<T>::value,
        add_value_const_t<std::remove_reference_t<T>>&,
        add_value_const_t<std::remove_reference_t<T>>&&
    >;
};
template<typename T>
struct add_value_const<
    T, std::enable_if_t<std::is_pointer<T>::value>
>
{
    using type = add_value_const_t<std::remove_pointer_t<T>>*;
};

在您的情况下,您必须使用foo<add_value_const<T>>而不是foo<const T>

我使用了C 14语法,但可以轻松移植到C 11。使用C 17,它更可读。

您可以在Godbolt上找到汇编示例。