Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do to have a template deduce its parameters

I am trying to write a sink for a back_inserter to reduce the amount of std::copy() commands that proliferate the code.

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

template <typename OutputIterator>
class sink
{
public:
    sink(OutputIterator out) : _out(out) { }
    OutputIterator _out;
};

template <typename OI, typename C>
sink<OI>& operator<<(sink<OI>& s, const C& c)
{
    std::copy(c.begin(), c.end(), s._out);
    return s;
}


int main(int, const char*[])
{
    std::vector<uint8_t> c;
//    auto s = sink<std::back_insert_iterator<std::vector<uint8_t>>>(std::back_inserter(c));
    auto s = sink(std::back_inserter(c));

    s << std::vector<uint8_t>{'F','e','e','d','i','n','g',' ','f','r','o','g','g','i','e','s'};
    s << std::string("Hungry hippos");

    std::copy(c.begin(), c.end(), std::ostream_iterator<int>(std::cout, ":"));
}

However this gives the error:

main.cpp: In function 'int main(int, const char**)':
main.cpp:27:18: error: missing template arguments before '(' token
     auto s = sink(std::back_inserter(c));
                  ^

The code below works but is less than desirable as it looks worse than having lots of std::copy function calls everywhere.

auto s = sink<std::back_insert_iterator<std::vector<uint8_t>>>(std::back_inserter(c));

How do I give the hint to the compiler to deduce the type automatically?

Eventually I would like to evolve the system so I can simply write

sink(out) << reply::stock_reply(reply::bad_request);

where out is a back_insert_iterator and stock_reply gives a canned response.

like image 236
graham.reeds Avatar asked Oct 17 '17 14:10

graham.reeds


People also ask

What is template argument deduction?

Template argument deduction is used when selecting user-defined conversion function template arguments. A is the type that is required as the result of the conversion. P is the return type of the conversion function template.

What is meant by templates parameters?

A template parameter is a special kind of parameter that can be used to pass a type as argument.

Which is correct example of template parameters?

For example, given a specialization Stack<int>, “int” is a template argument. Instantiation: This is when the compiler generates a regular class, method, or function by substituting each of the template's parameters with a concrete type.

How do you use template arguments in C++?

A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)


1 Answers

C++17 added this exact feature, along with surrounding help in cases where disambiguation is necessary. It's called class template argument deduction.

If that is not an option, you can resort to the workarounds such as "make" helper functions. This is what this would look like in your case (the forward is not strictly necessary for you here):

template<typename OutputIterator>
sink<std::decay_t<OutputIterator>> make_sink(OutputIterator&& output_iterator)
{
    return sink<std::decay_t<OutputIterator>>(std::forward<OutputIterator>(output_iterator));
}

Live demo here. The std::decay_t is so that the function does the right thing when passed an lvalue.

like image 103
rubenvb Avatar answered Oct 23 '22 00:10

rubenvb