如何使用元编程过滤const类型和非const类型?

e27*_*314 1 c++ template-meta-programming c++11 type-deduction

我有这个代码

#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;
}
Run Code Online (Sandbox Code Playgroud)

我试图在编译时知道常量参数和非常量参数的总大小.当前输出为8,由于某种原因,编译器认为b不是常量,我使用typeiddecltype打印类型ab输出显示确实b是一个int而不是const int我预期的.我错过了什么?是否有可能将一组可变参数分别为const参数和非const?

dyp*_*dyp 6

考虑这个功能模板:

template<typename T>
void deduce(const T&);
Run Code Online (Sandbox Code Playgroud)

如果让编译器T从参数表达式中推导出类型,则推导的类型将永远不会const:它将尝试使const T函数参数与用于调用函数的参数表达式的类型相同.例如:

struct cls {};
const cls c;

deduce(c) // deduces T == cls
Run Code Online (Sandbox Code Playgroud)

通过推导T == cls,编译器成功地使const T参数类型相同const cls.编译器没有理由为const和非const参数类型生成两个不同的函数; 在任何情况下,函数模板实例化的参数类型都将是const限定的:你通过说const T&而不是说来请求它T&.


您可以通过不对 cv限定函数参数来推断参数的常量:

template<typename T>
void deduce(T&);
Run Code Online (Sandbox Code Playgroud)

但是,这将无法绑定到非const临时值(rvalues).为了支持它们,您可以使用通用引用:

template<typename T>
void deduce(T&&);
Run Code Online (Sandbox Code Playgroud)

T如果参数是左值,这将推导出左值引用类型,如果参数是右值,则不会引用参考值.常量将被正确推导出来.

例如,如果参数具有类型const A且是左值,T则将推导出const A&.然后是函数参数const A& &&,它被折叠为const A&(左值引用).如果参数是rvalue,将推T导出const A,并且函数参数变为const A&&(rvalue-reference).

请注意,因为T在这种情况下可以作为引用,所以在检查const-ness之前需要删除它:std::is_const< typename std::remove_reference<T>::type >::value.