1

While going through the book "Effective STL" the author gives an example of how a copy_ifcould be written since this does not exist in the standard algorithms. Here is the authors version:

template <typename Input, typename Output,typename Predicate>
OutputIterator copy_if(Input begin , Input end, Output destBegin, Predicate p)
{
   while(begin != end)
   {
     if(p(*begin)) *destBegin++=*begin;
     ++ begin;
   }
   return destBegin; 
}

Now my question is how can the author use that method like this:

copy_if(widg.begin(),widg.end(),ostream_iterator<widg>(cerr,"\n"),isDefective);

My question is why isnt the template parameters being defined with copy_if (since it requires 3) such as this

copy_if<p1,p2,p3>(...)
TemplateRex
  • 69,038
  • 19
  • 164
  • 304
MistyD
  • 16,373
  • 40
  • 138
  • 240
  • 7
    `std::copy_if` does exist. It just wasn't around when the book was written. – chris Oct 05 '13 at 20:11
  • 1
    How can you write `std::cout << std::endl` and not `std::operator<<(std::cout, std::endl)`? – Kerrek SB Oct 05 '13 at 20:12
  • @KerrekSB thats one of the best examples. Many people are not aware about what `std::endl` is and why `<<` works if you are not using `using namespace std`. Two examples of "advanced" C++ behavior/features in the most common/simple C++ source line. – Manu343726 Oct 05 '13 at 20:25
  • @Manu343726: Thank you for noticing! I might offer "`<<<` as valid code" as a third point :-) – Kerrek SB Oct 05 '13 at 20:26
  • @KerrekSB what about `x --> 0`? :P – Manu343726 Oct 05 '13 at 20:35

2 Answers2

5

For function templates such as copy_if, the compiler can deduce the types of the template parameters from the function parameters. You don't have to supply them yourself, although I don't think it's an error if you do.

This is different from class templates where you do have to explicitly supply the template parameters.

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
john
  • 85,011
  • 4
  • 57
  • 81
  • 1
    In fact, it's recommended by STL (and for good reason) not to specify them unless you have a good reason to. – chris Oct 05 '13 at 20:12
  • 1
    @chris: [STL does indeed recommend it](http://channel9.msdn.com/Series/C9-Lectures-Stephan-T-Lavavej-Core-C-), but the [C++ standard library](http://stackoverflow.com/a/5205571/596781) also recommends it. – Kerrek SB Oct 05 '13 at 20:14
  • @KerrekSB, Interesting, didn't know it did as well, but it's only good that it does. – chris Oct 05 '13 at 20:15
  • 3
    the proper name is function template, not template function – TemplateRex Oct 05 '13 at 20:20
  • @KerrekSB do you have any quote from the Standard that actually recommends argument deduction? (not that any sane person would ever not use it) – TemplateRex Oct 05 '13 at 20:29
  • @TemplateRex: Hm, I know that `make_pair` *breaks* if you don't use deduction, though I'm not actually aware of an outright advisory note in the standard. I think it's more of a thing that follows from the properties of argument deduction... My earlier comment was much more of a stab against the abuse of the term "STL" than about what the standard says! – Kerrek SB Oct 05 '13 at 20:32
  • @KerrekSB that is because the `make_pair` parameters are rvalue references, so explicit template specification will only let them bind to rvalues, whereas with argument deduction, reference collapsing will also let them bind to lvalues. For C++98 code, I can't think of any breaking stuff, though. – TemplateRex Oct 05 '13 at 20:36
0

The type parameters of a function template could be deduced by the compiler from the parameters of the function. For example:

template<typename T>
auto return_value_type_instance(const std::vector<T>&) -> T
{
    return T();
}

This is an example of C++11 trailing return type, which return type will be bool if you pass a std::vector<bool> instance to the function , char if you pass a char vector, etc:

int main()
{
    std::vector<bool> a;
    std::vector<char> b;
    std::vector<float> c;

    bool  aa = return_value_type_instance(a);
    char  bb = return_value_type_instance(b);
    float cc = return_value_type_instance(c);
}

Or in a more common example, STL-like algorithms:

template<typename iterator_type>
void print_range(iterator_type begin , iterator_type end)
{
    for(iterator_type it = begin ; it != end ; ++it)
        std::cout << *it << std::endl;
}

int main()
{
    std::vector<int> v = {0,1,2,3};

    print_range(v.begin() , v.end());
}

Output:

0
1
2
3

Manu343726
  • 13,969
  • 4
  • 40
  • 75
  • @chris It compiles, but does implicit conversions, right? (Thats not the point of the example, was a typo I have fixed it yet). On the other hand the first example ist so overcomplicated (The trailing return type), thats the first example which have come to my mind. – Manu343726 Oct 05 '13 at 20:20