众所周知,以下函数指针具有不同的类型:
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
。但为什么呢?
答案 0 :(得分:5)
const
值参数不会影响任何形状或形式的签名。从非模板声明中删除引用时也是如此。 const
仅影响函数定义中参数的使用。如果添加引用或指向类型的指针,则更改内容,const
会影响函数的类型。
在嵌套类型中,T
是应用了int&
的{{1}}。但是,const
和T&
也是相同的类型。我想您的混淆源于您在{左侧T& const
的不明智的位置:const
更适用于顶级实体。
答案 1 :(得分:1)
已经给出了“为什么”这种情况发生的答案。这是解决问题的可能方法 - 将“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,它更具可读性。
您可以找到编译示例on godbolt。