当函数参数是const引用T时,为什么T'的模板参数推导会跳过数组元素的常量?

时间:2015-06-17 13:27:02

标签: c++ arrays template-deduction

让我们考虑一下这些定义:

/*** full type information with typeid ***/
template <class> class Type{};

template <class T> std::string typeStr()
{ return typeid(Type<T>).name(); }

/*** function template for parameter deduction ***/
template <class T> void func(const T &a)
{
    std::cout << "Deduced type for T is: " << typeStr<T>() << std::endl;
    std::cout << "\targument type is: " << typeStr<decltype(a)>() << std::endl;
}

指向const

的指针

如果执行以下语句:

const int i=5, *ip=&i;
func(ip);

输出结果为:

Deduced type for T is: 4TypeI**PKi**E

因此T实际上被推断为指向常量整数的指针。参数是const的引用这一事实不会改变推论,这是人们所期望的,因为指针的常量是低级的。

但是使用const

数组

但是,如果执行以下语句:

const int ia[3] = {3, 2, 1};
func(ia);

输出结果为:

Deduced type for T is: 4TypeI**A3_i**E

因此,T实际上被推导为3个 -const整数的数组。参数是const 的引用确实会改变推论,就像const正在滑入数组元素一样。

实际上,最多18个CL的版本推导T因为3个const整数的数组是我期望的标准,但似乎从第19节开始它收敛到GCC和Clang正在做的事情(即,推断为 -const)。

因此,我认为后来的行为是标准的,但理由是什么?它的表现与指针不同似乎令人惊讶。

编辑:在 dip 评论之后,我将在此处报告与此行为相关的CWG问题的指针,他实际发布的指针作为对this answer的评论(答案实际上提出了这个新问题...... C ++感觉就像一个深层隧道)

1 个答案:

答案 0 :(得分:1)

使用此功能模板原型:

template <typename T> void func(const T& a);

在第一个示例中,类型推导的工作原理如下:

const int* ip;

func(ip) => func<const int*>(const (const int*)& a)
                 ^^^^^^^^^^         ^^^^^^^^^^

注意:这是伪代码。完整类型为const int* const&

请注意,const int仍为const int,但*变为* const

这是因为const int*只是一个常规的,可变的,非易失性的指针。它只是*。它所指的是无关紧要的。

但是在第二个例子中,你有:

const int ia[3];

func(ia) => func<int[3]>(const (int[3])& a)
                 ^^^^^^         ^^^^^^

注意:这是伪代码。真实的类型是const int (&a)[3]

因此,类型推导在两种情况下都是相同的,丢弃外部const

恰好const数组与const元素数组相同。

写这样的类型可能会有所帮助:

template <typename T> func(T const & a);

int const * ip;

func(ip) => func<int const *>(int const * const & a)

int const ia [3];

func(ia) => func<int [3]>(int const (& a) [3])

在第二个例子中,const似乎“移动”从应用于阵列以应用于元素。这是因为你不能真正拥有const数组,只有const元素数组。