我在add_const
typetrait应用于转发引用类型的场景中使用它。看起来没有constness添加到类型中所以我做了一个小例子来验证是这种情况(PrintType
是一个不完整的类型,会导致编译错误,迫使编译器吐出模板的名称错误消息中的参数):
#include <iostream>
#include <type_traits>
#include <complex>
template <class T>
struct PrintType;
template <class T>
void f(T&& arg)
{
PrintType<std::add_const_t<decltype(arg)>> local;
(void)local;
}
int main()
{
std::complex<double> co;
f(co);
}
错误消息says:
main.cpp: In instantiation of 'void f(T&&) [with T = std::complex<double>&]':
main.cpp:20:9: required from here
main.cpp:12:48: error: 'PrintType<std::complex<double>&> local' has incomplete type
PrintType<std::add_const_t<decltype(arg)>> local;
即特质将我的类型转换为T = std::complex<double>&
而不是T = std::complex<double> const&
答案 0 :(得分:3)
类型特征按预期工作。您应该考虑您尝试做什么,即将constness添加到引用。 你不能重新绑定引用(它不可变),所以基本上任何引用都是const
引用
T& == T& const
我认为你期望做的是创建一个const类型的引用(这让我想起const iterator
vs const_iterator
thingy),这种方法不能这样做,原因相同你不能用这种方式将引用类型设置为对const类型的引用:
typedef T& ref_t;
typedef const ref_t const_ref_t; // This is not T const& !!
总而言之,将const添加到引用类型使其成为const引用(与引用相同)而不是对const
类型的引用
答案 1 :(得分:1)
对于这样的情况,拥有一个将引用转移到新类型的类型特征会很有用。这可以补充对const
和volatile
执行相同操作的另一个特征,几乎完全相同。在您的情况下,如果您使用T
而不是decltype(arg)
,则 只需要担心左值引用。但是,如果使用lambda,你肯定也需要担心rvalue引用。
以下是一个示例实现:
template<typename T, bool ApplyLvalueRef, bool ApplyRvalueRef>
struct apply_ref {
static_assert(!(ApplyLvalueRef && ApplyRvalueRef), "Improper use: T cannot be & and &&");
using possibly_lref = std::conditional_t<
ApplyLvalueRef,
std::add_lvalue_reference_t<T>,
T
>;
using type = std::conditional_t<
ApplyRvalueRef,
std::add_rvalue_reference_t<possibly_lref>,
possibly_lref
>;
};
template<typename From, typename To>
struct transfer_ref : apply_ref<To, std::is_lvalue_reference<From>{}, std::is_rvalue_reference<From>{}> {};
template<typename From, typename To>
using transfer_ref_t = typename transfer_ref<From, To>::type;
乍一看,对于左值与右值相比,单独的布尔值似乎有点傻。但是,这允许不应用。永远不应该存在两者都是真的情况,这是由静态断言强制执行的。
现在我们可以轻松编写函数:
template <class T>
void f(T&& arg)
{
using with_const = std::add_const_t<std::remove_reference_t<T>>;
PrintType<transfer_ref_t<T, with_const>> local;
(void)local;
}
由于我们无法将const
应用于引用,因此我们必须将其删除,将const
添加到引用类型,然后再添加引用。