C ++函数模板格式

时间:2016-04-16 05:16:19

标签: c++ templates

刚才有关于课程模板的问题:

对于下面的代码,该函数运行完全正常,但我很困惑为什么/如何运行fill函数而不给迭代器的类/类型(为什么你不需要提供迭代器类型):

#include <vector>
#include <iostream>
#include <typeinfo>

template<typename Iter>
void fill(Iter first, Iter limit, int value){
  while (first != limit) {
    *first = value;
    ++first;
  }
}
int main() {
  std::vector<int> vec1 {2, 4, 6, 1, 9};
  fill(vec1.begin(), vec1.end(), 7);
}

无论如何,我的实际问题如下:

我只想做template <typename Iter, typename A>,所以我可以在函数中指定值变量的数据类型(而不是必须在函数模板中明确地命名int)

然而,当我尝试fill<int>(...)这个思路时,该程序根本无法正确编译:

#include <vector>
#include <iostream>
#include <typeinfo>

template<typename Iter, typename A>
void fill(Iter first, Iter limit, A value){
  while (first != limit) {
    *first = value;
    ++first;
  }
}
int main() {
  std::vector<int> vec1 {2, 4, 6, 1, 9};
  fill<int>(vec1.begin(), vec1.end(), 7);
}

基本上我很好奇如何更改模板以允许单个fill<datatype of value>(arg1,arg2...)函数仍然正确接受迭代器而不显式命名它们。

谢谢!

编辑:使用::fill结束!感谢大家的知识和信息!

4 个答案:

答案 0 :(得分:2)

您的实际问题

您正在调用第二个功能模板。如果要指定特定的模板参数,则必须在您真正要指定的参数之前指定每个参数。

e.g。

fill<std::vector<int>::iterator, int>(std::begin(vec), std::end(vec), 5);

即便如此,您的代码也无法编译。

你的第二个原型不能编译的原因是因为ADL在fill命名空间中找到另一个名为std的函数,该函数与你的原型相同,并且不能决定是否使用你的版本或std内的版本。要解决这个问题,只需像这样调用fill

::fill(vec.begin(), vec.end(), 5);

在全局命名空间中显式调用fill

您的第一个问题:

调用函数模板,因为它实际上是一个模板,将用于编译器将要使用的实际函数,或者您将显式实例化。

编译器在调用站点上计算出参数的类型,并根据它调用函数模板的正确实例。

它类似于函数参数重载。

E.g。这样:

template<typename T>
auto fn(T arg){
    std::cout << arg << std::endl;
}

auto main() -> int{
    fn(1); // compiler sees you pass an int
    fn(1.0); // compiler sees you pass a double
}

与此相同:

auto fn(int i){
    std::cout << i << std::endl;
}

auto fn(double d){ // heh, double d
    std::cout << d << std::endl;
}

auto main() -> int{
    fn(1);
    fn(1.0);
}

答案 1 :(得分:2)

它不起作用的原因是因为您将第一个模板参数Iter指定为int,但它不是迭代器的类型,因此是错误。

您必须指定模板参数,因为如果不这样做,参数依赖查找将找到具有相同签名的std::fill,并且存在歧义。

你可以做些什么来解决它:

  • 更改模板参数的顺序,因此推导出Iter,您可以指定Atemplate<typename A, typename Iter>
  • 使用分数解析运算符明确表示您希望自己的函数(不是std::):::fill(vec1.begin(), vec1.end(), 7);

答案 2 :(得分:0)

  

我只是想做模板,所以我可以在函数中指定value变量的数据类型(而不是在函数模板中明确地命名int)

你真正想要的(评论内联):

#include <iterator>
#include <vector>


template<class Iter>
Iter myfill(
  // deduce template argument from this
            Iter first,

  // and this
            Iter last,  

  // std::iterator_traits<>::value_type deduces the value type that the
  // iterator is iterating over - i.e. what it's 'pointing at'
  // we need typename because iterator_traits<Iter> is dependent on the deduction
  // of Iter
            const typename std::iterator_traits<Iter>::value_type& v)
{
  while (first != last) {
    *first++ = v;
  }
  return first;
}

int main()
{
  std::vector<int> v1(20);
  myfill(std::begin(v1), std::end(v1), 20);

  myfill(std::begin(v1), 
         std::end(v1), 
         20.0); // NOTE: conversion will happen at the call site
  // myfill<std::vector<int>::iterator> will still be selected

}

答案 3 :(得分:-1)

我想你需要将Iterator也作为参数传递,如

std::vector< int >::iterator 

因为模板需要这样做 此外,它将是一个模糊的调用,因为std::vector namespace中已存在填充方法 你可以做的是将填充方法重命名为myfill并且它有效;)