C++ 为什么将常量对象传递给需要非常量模板类型参数的模板化函数会导致编译错误?
考虑以下模板化函数:C++ 为什么将常量对象传递给需要非常量模板类型参数的模板化函数会导致编译错误?,c++,templates,C++,Templates,考虑以下模板化函数: template <template<class, class> class V, class T, class Allocator> void fn(V<T, Allocator>& v) { for (T& t : v) { std::cout << t << std::endl; } } 编译器很高兴,我也很高兴。但是,当我传递fn()aconst向量时: std::vect
template <template<class, class> class V, class T, class Allocator>
void fn(V<T, Allocator>& v)
{
for (T& t : v) {
std::cout << t << std::endl;
}
}
编译器很高兴,我也很高兴。但是,当我传递fn()
aconst
向量时:
std::vector<int> v{ 1, 2, 3, 4, 5 };
fn(v);
const std::vector<int> v{ 1, 2, 3, 4, 5 };
fn(v);
向量v{1,2,3,4,5};
fn(v);
一切都很糟糕。这将导致编译错误。对于GCC 4.9.2,错误消息为:
In function 'int main()':
17:7: error: invalid initialization of reference of type 'std::vector<int>&' from expression of type 'const std::vector<int>'
7:6: note: in passing argument 1 of 'void fn(V<T, Allocator>&) [with V = std::vector; T = int; Allocator = std::allocator<int>]'
函数“int main()”中的:
17:7:错误:从“const std::vector”类型的表达式初始化“std::vector&”类型的引用无效
7:6:注意:在传递'void fn(V&)[带V=std::vector;T=int;Allocator=std::Allocator]'的参数1时
我认为V&
将被推导出const std::vector&
。然而,情况并非如此。为什么会这样
我认为V&
将被推导出const std::vector&
如果参数是普通的U
,如模板void fn(U&),则为真代码>
类型推断是模式匹配const
是类型的一部分,因此模式U
可以推断为T const
。考虑:
using T = int const;
T var;
template<class U>
void fn(U&);
fn(var); // -> fn<int const>(int const&);
// We deduce U = T = int const
但是,模式V
是一个模板实例化,而不是任何类型。最后,我们需要使函数原型与调用站点兼容。所以我们需要推导出V,这样我们就得到了void fn(向量常数)代码>。只有当我们将V
推断为元函数时,这才有效:
template <template<class, class> class V, class T, class Allocator>
void fn(V<T, Allocator>& v)
{
for (T& t : v) {
std::cout << t << std::endl;
}
}
template<class U>
using M = vector<U> const;
template<template<class> class V, class T>
void fn(V<T>&);
M<int> var;
fn(var); // ?? fn<M, int>(M<int>);
如果一个函数声明期望一个非常量,这意味着它想要对它进行变异。编译器不允许这样做是有道理的。如果函数不改变参数,则将参数作为常量引用/指针传递是一条经验法则。函数通过非const
引用接受参数,这意味着(对于调用方而言)函数可能会更改其参数。const
对象是一个不打算(逻辑上)更改的对象。将一个打算保持不变的对象传递给一个可能改变它的函数是无效的——因此第二种情况下的诊断是无效的。由于您没有修改对象,因此最好使用for(T const&T:v)
。(并且std::endl
会导致缓冲区刷新,因此您可以将其替换为'\n'
,以获得更好的性能)。。。。但有趣的是,为什么V的常量限定被取消了…@JHBonarius,这是一个很好的骗局。你为什么不喜欢这个答案?这能回答你的问题吗?这可能是alias模板仅在C++11中起作用的结果。。。扣减规则在那一点上已经写好了。
void fn<..>(vector<int> const&)
{
template<class T>
using U = vector<T> const;
// ...
}