我有这段代码
#include <iostream>
size_t F()
{
return 0;
}
template <class Type, class... NextTypes>
size_t F(const Type& type, const NextTypes&... nextTypes)
{
if (!std::is_const<Type>::value)
return sizeof(type) + F(nextTypes...);
else
return F(nextTypes...);
}
int main()
{
int a = 0;
const int b = 0;
const size_t size = F(a,b);
std::cout << "size = " << size << std::endl;
return 0;
}
我试图在编译时知道常量参数和非常量参数的总大小。当前输出为8,由于某种原因,编译器认为b
不是常数,我使用typeid
和decltype
来打印a
和{{1}的类型确实输出显示b
是b
而不是int
,正如我预期的那样。我错过了什么?是否可以将可变参数集合分离为const参数和非const?
答案 0 :(得分:6)
考虑这个功能模板:
template<typename T>
void deduce(const T&);
如果让编译器从参数表达式推导出T
的类型,推导出的类型将永远不会是const
:它会尝试使函数参数的const T
相同到用于调用函数的参数表达式的类型。例如:
struct cls {};
const cls c;
deduce(c) // deduces T == cls
通过推导T == cls
,编译器成功地使const T
与参数类型const cls
相同。编译器没有理由为const和非const参数类型生成两个不同的函数;在任何情况下,函数模板实例化的参数类型都将是const限定的:您通过说const T&
而不是T&
来请求它。
您可以通过 cv-限定函数参数来推断出参数的常量:
template<typename T>
void deduce(T&);
但是,这将无法绑定到非const临时值(rvalues)。为了支持它们,您可以使用通用引用:
template<typename T>
void deduce(T&&);
如果参数是左值,这将推导出T
的左值引用类型,如果参数是右值,则不会引用参考类型。这个常数将被正确推导出来。
例如,如果参数的类型为const A
并且是左值,则T
将推断为const A&
。然后,函数参数为const A& &&
,折叠为const A&
(左值参考)。如果参数是右值,则T
将推导为const A
,函数参数将变为const A&&
(右值参考)。
请注意,由于T
在这种情况下可以作为引用,因此您需要在检查const-ness之前将其删除:std::is_const< typename std::remove_reference<T>::type >::value
。