问题
Just had a question about class templates:
For the following code, the function runs totally fine, but I am confused as to why/how you can run the fill function without giving a class/type for the iterators (why you don't need to supply the iterator type):
#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);
}
Regardless, my actual question is the following:
I just wanted to do template <typename Iter, typename A>
, so I could specify the datatype of the value variable in the function (rather than having to name int explicitly in the function template)
However, when I try fill<int>(...)
with this train of thought, the program doesn't compile correctly at all:
#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);
}
Basically I just was curious how you could change the template to allow for a single fill<datatype of value>(arg1,arg2...)
function that still accepts the iterators correctly without explicitly naming them.
Thanks!
edit: Ended up using ::fill
! Thank you everyone for the knowledge and information!
回答1:
Your actual question
You're calling your second function template wrong. If you want to specify a specific template parameter you must specify each parameter before the one you really want to specify too.
e.g.
fill<std::vector<int>::iterator, int>(std::begin(vec), std::end(vec), 5);
Also even then your code won't compile.
The reason why your second prototype doesn't compile is because ADL is finding another function named fill
within the std
namespace that has an identical prototype to yours and can't decide whether to use your version or the one within std
. To fix this simply call fill
like this:
::fill(vec.begin(), vec.end(), 5);
Which is explicitly calling the fill
in the global namespace.
Your first question:
A function template is called that because it is literally a template that will be used for a real function the compiler will, or you will explicitly instantiate.
The compiler figures out the type of the arguments at the calling site and calls the right instantiation of the function template based on that.
It is analogous to function argument overloading.
E.g. this:
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
}
is the same as this:
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);
}
回答2:
The reason it doesn't work because you are specifying the first template argument Iter
as an int
, but it's not the type of the iterator, hence the error.
You have to specify a template argument because if you don't, Argument Dependent Lookup will find std::fill
with the same signature, and there is an ambiguity.
What you could do to fix it:
- Change the order of the template arguments, so
Iter
gets deduced and you can specifyA
:template<typename A, typename Iter>
- Explicitly state that you want your function (not the
std::
one) with the score resolution operator:::fill(vec1.begin(), vec1.end(), 7);
回答3:
I just wanted to do template , so I could specify the datatype of the value variable in the function (rather than having to name int explicitly in the function template)
What you really wanted (comments inline):
#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
}
回答4:
I guess u need to pass also Iterator as argument like
std::vector< int >::iterator
Because template expects that
Plus it would be then ambiguous call because already fill method exists within std::vector namespace
What you can do is rename that fill method as myfill and it works ;)
来源:https://stackoverflow.com/questions/36660394/c-function-template-formatting