如何使用元编程过滤常量类型和非常量类型

How to filter const types and non const types using meta programing?

本文关键字:常量 类型 非常 过滤 何使用 编程      更新时间:2023-10-16

我有这个代码

#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不是常数,我使用typeiddecltype打印ab的类型,实际上输出显示bint,而不是我预期的const int。我错过了什么?有可能将一组可变参数分为常量参数和非常量参数吗?

考虑这个函数模板:

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 T&而不是说T&来请求它。


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

template<typename T>
void deduce(T&);

但是,这将无法绑定到非常量临时值(rvalues)。为了支持它们,您可以使用通用参考:

template<typename T>
void deduce(T&&);

如果参数是左值,这将推导出T的左值引用类型,如果参数是右值,则不推导出引用类型。常数将被正确地推导出来。

例如,如果参数的类型为const A并且是左值,则T将被推导为const A&。函数参数是const A& &&,它被折叠为const A&(左值引用)。如果自变量是右值,则T将被推导为const A,并且函数参数变为const A&&(右值引用)。

注意,由于T在这种情况下可以是一个引用,因此在检查常量之前需要删除它:std::is_const< typename std::remove_reference<T>::type >::value