C ++函数模板:必须使用&对于参数类型和返回类型?

时间:2017-11-04 07:59:19

标签: c++ function templates

我正在学习使用功能模板。我发现如果我将参数类型声明为引用,程序将起作用。但如果参数类型不是引用,我会收到错误。例如:

以下代码打印正确的结果,无错误。

#include <iostream>
using namespace std;

template <typename T>
T & max (T & a, T & b){
    return a>b?a:b;
}

int main(int argc, char const *argv[])
{
    cout << max(1,2) << endl;
    return 0;
}

但如果我删除了代码中的所有“&”,即更改上述程序如下:

#include <iostream>
using namespace std;

template <typename T>
T  max (T  a, T  b){
    return a>b?a:b;
}

int main(int argc, char const *argv[])
{
    cout << max(1,2) << endl;
    return 0;
}

此代码将导致以下错误。

a.cpp: In function ‘int main(int, const char**)’:
a.cpp:11:17: error: call of overloaded ‘max(int, int)’ is ambiguous
  cout << max(1,2) << endl;
                 ^
a.cpp:5:4: note: candidate: T max(T, T) [with T = int]
 T  max (T  a, T  b){
    ^~~
In file included from /usr/include/c++/7/bits/char_traits.h:39:0,
                 from /usr/include/c++/7/ios:40,
                 from /usr/include/c++/7/ostream:38,
                 from /usr/include/c++/7/iostream:39,
                 from a.cpp:1:
/usr/include/c++/7/bits/stl_algobase.h:219:5: note: candidate: constexpr const _Tp& std::max(const _Tp&, const _Tp&) [with _Tp = int]
     max(const _Tp& __a, const _Tp& __b)

为什么呢? 谢谢大家的帮助!

3 个答案:

答案 0 :(得分:2)

第一个示例中未考虑引用参数版本,因为这些常量不符合可修改的左值引用。并且由于不明智的var poly; var map; var infodatajson = [ 17.4172192, 78.401285, 17.418407, 78.401629, 17.418090, 78.400610, 17.417865, 78.398234 ]; // for center the map function initMap() { map = new google.maps.Map(document.getElementById('map'), { zoom: 15, center: { lat: 17.4172192, lng: 78.401285 } }); // for polyline var flightPlanCoordinates = new Array(); for (i = 0; i < infodatajson.length; i += 2) { var point = new google.maps.LatLng(infodatajson[i], infodatajson[i + 1]); flightPlanCoordinates.push(point); } poly = new google.maps.Polyline({ path: [new google.maps.LatLng(17.4172192, 78.401285), new google.maps.LatLng(17.418407, 78.401629), new google.maps.LatLng(17.418090, 78.400610), new google.maps.LatLng(17.417865, 78.398234) ], geodesic: true, strokeColor: '#0000FF', strokeOpacity: 1.0, strokeWeight: 3, }); var infowindow; var infodata; var marker; // for markers for (var i = 0, ln = infodatajson.length; i < ln; i += 2) { infodata = infodatajson[i] + ", " + infodatajson[i + 1]; marker = new google.maps.Marker({ position: new google.maps.LatLng(infodatajson[i], infodatajson[i + 1]), map: map, title: infodatajson[i] + ", " + infodatajson[i + 1], }); infowindow = new google.maps.InfoWindow({}); //function bindInfoWindow(marker, map, infowindow, infodata) { marker.addListener('click', function() { infowindow.setContent(infodata); infowindow.open(map, this); }); //} } poly.setMap(map); } ,您正在提取using namespace std;版本,这将起作用。您可以在第一个版本中删除您的std代码并且它仍然有效,因为一旦这些引用触发取消资格,就不会考虑它。

简而言之,第一个版本不考虑您的max代码,因为它不符合条件,因此使用max代替( 符合条件)。在第二个版本中,使用值参数的代码和使用const-references的std::max版本都可以限定,因此结果不明确。

答案 1 :(得分:2)

在std名称空间中已经存在具有相同(或兼容)名称和参数类型的函数(模板)。

删除

using namespace std;

用cd ::

作为cout和endl的前缀
std::cout << max(1,2) << std::endl;

否则,您已使用std命名空间中的所有名称污染了全局命名空间。

答案 2 :(得分:0)

有一个模板max()函数接受名称空间std中的参数(在标准标题<algorithm>中)。虽然标准并不要求#include <iostream>引入该功能,但它也不禁止它。您的标准编译器会通过<iostream>引入它。

using指令(using namespace std)使std::max()个模板被视为代码中匹配函数的候选者。

在您的第一个代码示例中,调用max(1,2)std::max()匹配,因为它接受const引用,并且比您接受非const的函数更好匹配参考。它恰好产生了你期望的输出。

在您的第二个代码示例中,按值传递,编译器没有理由更喜欢您的max()std中的那个(通过值传递或通过const引用两者同样适用于传递int文字,如12)。因此,编译器抱怨模棱两可。

问题是:使用不同的编译器(或其标准库),您的代码可能会以不同的方式失败,因为<iostream>不需要声明std::max(),而不是所有实现都这样做。

删除using指令,代码中std::max()的潜在用法将消失 - std::max()将不会被视为您的任何代码示例中的候选对象。您的第一个示例将无法编译,因为非const引用不能用于传递文字值。第二个将编译并生成您期望的输出。这种行为在符合标准的C ++编译器之间是一致的(并且不会影响<iostream>之类的标准头是否声明std::max()