How can I call a template function in another template function - c++

I tried to write a generic print function in C++14. But template printItem function can not instantiate.
template <class T>
void printItem(T t)
{
std::cout << t << std::endl;
}
template <class T>
void printVector(T t)
{
for_each(t.begin(), t.end(), printItem);
}
int main()
{
std::vector<std::string> vs = {"word1", "word2"};
printVector(vs);
}
This code causes a compiler error:
no matching function for call to
'for_each(std::vector<std::__cxx11::basic_string<char> >::iterator, std::vector<std::__cxx11::basic_string<char> >::iterator, <unresolved overloaded function type>)'

printItem is a function template, and it cannot deduce the argument type, so you need to specify that, like this:
for_each(t.begin(), t.end(), printItem<typename T::value_type>);
Additionally, there appears to be a typo in printItem. You don't need to dereference t at all.
If you are not using this function anywhere else, then you can define it inline using a lambda, like this:
for_each(t.begin(), t.end(), [](auto s) { std::cout << s << std::endl; });
Note that the lambda operator() is also templated in this case, however the type can be deduced, so it's fine.
Also, std::for_each is often a code smell, in my opinion. It can be replaced by the much more readable:
for (auto const &s : t)
std::cout << s << std::endl;

There is no way for the compiler to know which printItem specialisation you wanted, with the information available to it according to the standard at that point.
So, this syntax is not available here.
This is what you need:
for_each(t.begin(), t.end(), printItem<typename T::value_type>);
Being able to do this kind of thing is exactly why containers are required to define type aliases like value_type; you end up needing them all over the place.
A limitation in the language? Perhaps. But it does help avoid corner cases.
Having to use typename here certainly is an annoyance, though.
Your code, to be honest, would be a lot easier and clearer if you just used a loop:
for (const auto& item : t)
printItem(item);
In the time of ranged-for and all that lovely stuff, for_each is not all that useful for common cases any more.
Also, take the arguments by reference-to-const, and remove the erroneous dereference. I'll also remove the repeated std::endl, which is performing stream flushing you don't need.
template <class T>
void printItem(const T& t)
{
std::cout << t << '\n';
}
template <class T>
void printVector(const T& t)
{
for (const auto& item : t)
printItem(t);
}
int main()
{
std::vector<std::string> vs = {"word1", "word2"};
printVector(vs);
}
Finally, it's a good idea to let functions like printItem take a reference to the stream you want to use, so that you could pick (say) a std::stringstream rather than only std::cout.

Related

return a reference to an array with templated size

I am trying a function's return value to be to a reference to an array whose size is variable (i.e. templated). The code I have is:
const char *strarr[] = { "one", "two", "three" };
template <std::size_t T>
const char* (&GetArr())[T]
{
return strarr;
}
The reason I want to do it this way: it would be convenient in my case to then use in a a loop such that:
for (const auto& s : GetArr()) { std::cout << s << std::endl; }
but this wouldn't compile. the only way to use it is to specify the size in GetArr(); but I was wondering why it can't deduce the size by itself, as it would have if I passed a reference to this array as a parameter to a templated function, as in:
template <std::size_t T>
void PrintArray(const char* (&arr)[T])
{
for (const auto& s : arr)
{
std::cout << s << std::endl;
}
}
which does work.
There is no template argument deduction from return statements and T cannot be deduced from any function parameter/argument pair.
So you will have to specify the size manually, but that is not a problem, since you need to specify the array that is returned anyway, so that the only possible choice is
const char* (&GetArr())[std::size(strarr)]
{
return strarr;
}
That said, there is return type deduction via type placeholders which you can make use of here easily:
auto& GetArr()
{
return strarr;
}
Note that in both cases the function is not a function template. There aren't multiple different instantiations that would make sense for it. There is only one possible size that makes sense, one possible return type and one possible function body. Therefore template <std::size_t T> doesn't really make sense to begin with.
However, it is much simpler to just use std::array instead of built-in arrays. The former doesn't require you to take care of special language rules or weird declaration syntax as in the first example.
There is also no need to write PrintArray so restrictively. You can instead write
template <typename R>
void PrintRange(const R& r)
{
for (const auto& s : r)
{
std::cout << s << std::endl;
}
}
and now you have a function that will work with any range, whether built-in array, std::array, std::vector, std::list, etc.

Template type inference using std::views

I am coming somewhat belatedly to Functional Programming, and getting my head around ranges/views. I'm using MSVC19 and compiling for C++ 20.
I'm using std::views::transform and the compiler doesn't seem to be inferring type as I might naively hope.
Here's a small example, which simply takes a vector of strings and computes their length:
#include <vector>
#include <iostream>
#include <ranges>
template<typename E>
auto length(const E& s)
{
std::cout << "Templated length()\n";
return static_cast<int>(s.length());
}
template<typename E>
auto getLengths(const std::vector<E>& v)
{
return v | std::views::transform(length<E>);
}
int main()
{
std::vector<std::string> vec = { "Larry","Curly","Moe" };
for (int i : getLengths(vec))
{
std::cout << i << "\n";
}
return 0;
}
with the output:
Templated length()
5
Templated length()
5
Templated length()
3
My question is why does changing the code in this line (dropping the <E>):
return v | std::views::transform(length);
give me an armful of errors, starting with: Error C2672 'operator __surrogate_func': no matching overloaded function found ?
Why doesn't the compiler infer that the type is std::string? If I replace the templates with a non-templated function:
auto length(const std::string& s) -> int
{
std::cout << "Specialized length()\n";
return static_cast<int>(s.length());
}
The code compiles and runs, so clearly without the template, the compiler finds a match for the particular type I am using.
This has nothing to do with views. You can reduce the problem to:
template <typename T>
int length(T const& x) { return x.length(); }
template <typename F>
void do_something(F&& f) {
// in theory use f to call something
}
void stuff() {
do_something(length); // error
}
C++ doesn't really do type inference. When you have do_something(length), we need to pick which length we're talking about right there. And we can't do that, so it's an error. There's no way for do_something to say "I want the instantiation of the function template that will be called with a std::string - it's entirely up to the caller to give do_something the right thing.
The same is true in the original example. length<E> is a concrete function. length is not something that you can just pass in.
The typical approach is to delay instantiation by wrapping your function template in a lambda:
void stuff() {
do_something([](auto const& e) { return length(e); }); // ok
}
Now, this works - because a lambda is an expression that has a type that can be deduced by do_something, while just length is not. And we don't have to manually provide the template parameter, which is error prone.
We can generalize this with a macro:
#define FWD(arg) static_cast<decltype(arg)&&>(arg)
#define LIFT(name) [&](auto&&... args) -> decltype(name(FWD(args)...)) { return name(FWD(args)...); }
void stuff() {
do_something(LIFT(length));
}
Which avoids some extra typing and probably makes the intent a little clearer.

Can a templated function be a template argument to another function?

I thought I'd benchmark some sorting algorithms, but I must be doing templates incorrectly:
Code
#include <iostream>
#include <vector>
template <typename ForwardIterator>
void dummysort(ForwardIterator begin_it, ForwardIterator end_it)
{
// pretend to use these and sort stuff
++begin_it;
++end_it;
}
template<typename SortFunc>
void benchmark(const char* name, SortFunc sort_func, std::vector<int> v)
{
std::cout << name << std::endl;
sort_func(v.begin(), v.end());
}
int main()
{
std::vector<int> first = {3, 2, 1};
benchmark("bubblesort", dummysort, first);
}
Error
10:48 $ clang -std=c++14 tmp.cpp
tmp.cpp:30:5: error: no matching function for call to 'benchmark'
benchmark("bubblesort", dummysort, first);
^~~~~~~~~
tmp.cpp:20:6: note: candidate template ignored: couldn't infer template argument 'SortFunc'
void benchmark(const char* name, SortFunc sort_func, std::vector<int> v)
^
1 error generated.
Compiler Info
10:47 $ clang --version
Apple LLVM version 8.1.0 (clang-802.0.42)
Target: x86_64-apple-darwin16.0.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/
If I "untemplate" dummysort, it works.
void dummysort(std::vector<int>::iterator begin_it, std::vector<int>::iterator end_it)
Question
Is there a way I can make it work generically, or, if not, can someone please give me a good explanation or thought experiment similar to this answer?
As explained by nwp, a template function isn't a function; is only a recipe to construct a function.
So you can't pass the recipe
benchmark("bubblesort", dummysort, first);
but you can do it explicating the type an constructing a function from the recipe; I mean
benchmark("bubblesort", dummysort<std::vector<int>::iterator>, first);
Works but I find it a little ugly.
I propose you another solution: instead of a template function, construct a class (or struct) with a template operator() in it; something like
struct dummySort
{
template <typename FI>
void operator() (FI begin_it, FI end_it)
{
++begin_it;
++end_it;
}
};
In this way you can call benchmark() passing an object of this type without explicating the type of the iterator: it's the call to operator inside of benchmark() that select the right type and construct the right operator.
The following is a full compiling example
#include <iostream>
#include <vector>
struct dummySort
{
template <typename FI>
void operator() (FI begin_it, FI end_it)
{ ++begin_it; ++end_it; }
};
template <typename SortFunc>
void benchmark (char const * name, SortFunc sort_func, std::vector<int> v)
{
std::cout << name << std::endl;
sort_func(v.begin(), v.end());
}
int main()
{
std::vector<int> first = {3, 2, 1};
benchmark("bubblesort", dummySort{}, first);
}
There are a few ways around this problem.
You could explicitly specify the template arguments for dummysort or you could static_cast it to the appropriate function pointer type. This, to me, is a pretty bad solution as it locks into a specific overload choice rather than relying on the language's overload rules. If you change other arguments or types, you could get (best-case) broken code or (worst-case) code that works but does something unexpected
You could lift your function template to be a function object that has a call operator template:
struct dummysort_t {
template <typename ForwardIterator>
void operator()(ForwardIterator begin_it, ForwardIterator end_it) const {
/* ... */
}
} constexpr dummysort{}; // in C++17, also mark inline
This allows you to just directly pass in dummysort to your function templates everywhere with the same expected behavior. The downsides to this solution are if you don't own dummysort, this is of course a non-starter, and if you use dummysort as a customization point, you need to do quite a bit more work to get this to have the expected behavior.
You could wrap it in a lambda. Since we're copying iterators, the simple form just works:
[](auto b, auto e) { dummysort(b, e); }
This delays template instantiation for dummysort until the other function template actually invokes it. This gives you the exact behavior you want, and will work in all situations (and fixes the issues with #2). More generally, this pattern should be used like:
#define OVERLOADS_OF(name) [&](auto&&... args) -> decltype(name(std::forward<decltype(args)>(args)...)) { return name(std::forward<decltype(args)>(args)...); }
with which you would pass:
OVERLOADS_OF(dummysort)
which for this particular case is overkill, but is more generally useful.
Two minor comments: You should pass the v parameter to benchmark by reference std::vector<int> &v and not by value std::vector<int> v, since vectors are expensive objects to construct. And std::endl is unnecessary with the standard streams; instead of
std::cout << "Value of the variable:" << std::endl;
std::cout << variable << std::endl;
you can just write
std::cout << "Value of the variable:\n";
std::cout << variable << '\n';
Which is both a lot less verbose and faster (not that it matters for the trivial case here).
To answer your question, no, the compiler would not be able to infer dummysort's template parameter in this case, so you would have to write it dummysort<std::vector<int>::iterator>. But there are ways you can simplify it:
1) If your compiler supports C++14 variable templates you can declare
template<typename T>
constexpr auto vecdummysort = dummysort<typename std::vector<T>::iterator>;
And then use it like
benchmark("bubblesort", vecdummysort<int>, first);
2a) With C++11 you can create an alias template
template<typename T>
using veciter = typename std::vector<T>::iterator;
Which lets you use dummysort like
benchmark("bubblesort", dummysort<veciter<int>>, first);
2b) For the same vecdummysort function as in example #1:
template<typename T>
void vecdummysort(veciter<T> first, veciter<T> last) {dummysort(first, last);}
3) You could also change the call to sort_func in benchmark to use raw pointers instead of iterators, so
sort_func(v.data(), v.data() + v.size());
Instead of
sort_func(v.begin(), v.end());
Which means you would be able to use benchmark like
benchmark("bubblesort", dummysort<int*>, first);
4) You can change the interface of dummysort to take the collection itself as the argument instead of iterators, which sacrifices a tiny bit of flexibility (e.g. if you wanted to sort only part of the collection, or use reverse iterators, and so forth) for a less verbose and more ergonomic interface
template<typename Collection>
void dummysort(Collection &c)
{
auto first = std::begin(c);
auto last = std::end(c);
}
Usage:
// benchmark()
sort_func(v);
// main()
benchmark("bubblesort", dummysort<std::vector<int>>, first);

How to have template type deduced in std::function arguments with lambda?

I have a boost::variant and I would like to execute a functor only if the variant is of a special type, so I made up this function:
template<typename T, typename Variant>
void if_init(Variant& opt_variant, std::function<void(T)> functor){
if(auto* ptr = boost::get<T>(&opt_variant)){
functor(*ptr);
}
}
This works well, but I would like the type T to be deduced, so that I can write that:
if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
But the type is not deduced:
type_inference.cpp:19:5: error: no matching function for call to 'if_init'
if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
^~~~~~~
type_inference.cpp:10:6: note: candidate template ignored: failed template argument deduction
void if_init(Variant& opt_variant, std::function<void(T)> functor){
If I write:
if_init<double>(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
it works well.
Is there a way to have type T being deduced ? I would like to type T only once. Here the type is short, but in the real case, there are long types.
I'm using CLang 3.2.
Here is the full test case (the first call compiles not the second):
#include <iostream>
#include <functional>
#include <boost/variant.hpp>
typedef boost::variant<int, double> Test;
template<typename T, typename Variant>
void if_init(Variant& opt_variant, std::function<void(T)> functor){
if(auto* ptr = boost::get<T>(&opt_variant)){
functor(*ptr);
}
}
int main(){
Test b = 1.44;
if_init<double>(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
if_init(b, [](int var){ std::cout << "I'm int and set" << std::endl; });
return 0;
}
I recommend you think of std::function<Sig> as a container of any one functor that conforms to Sig as a signature -- and which can be replaced at any moment. This functionality comes in very handy for e.g. std::vector<std::function<Sig>> because such a container can then hold functors of different types.
In your case, because you only care to have just the one functor you really don't need the functionality of std::function<Sig>. As such, I recommend you declare your function template like so:
template<typename T, typename Variant, typename Functor>
void if_init(Variant& opt_variant, Functor functor);
If you are worried that this doesn't communicate that Functor must conform to a void(T) signature, please note that std::function<Sig> does not enforce that either: although obviously you will end up with a compilation error, it is not a nice one. It's planned to be changed (and maybe your implementation has that either), but changed to a different kind of error. Still not that helpful for your case.
I personally make use of template aliases (in the template parameter list) to both document and enforce what a functor should conform to. This ends up looking like:
// Documents that e.g. long l = std::forward<Functor>(functor)(42.)
// should be a valid expression -- a functor that returns int would
// also be accepted.
// Triggers a hard-error (typically a static_assert with a nice message)
// on violation.
template<typename Functor, Requires<is_callable<Functor, long(double)>>...>
R foo(Functor functor);
// Documents that this function template only participates in overload resolution
// if the functor conforms to the signature.
// Does not trigger a hard-error (necessary by design); if everything goes right
// then another overload should be picked up -- otherwise an error of the kind
// 'no matching overload found' is produced
template<typename Functor, EnableIf<is_callable<Functor, long(double)>>...>
R bar(Functor functor);
As to your exact question, the rules of C++ do not allow for a template parameter to be deduced in your case. It's really not an easily fixed 'problem', if it is one. You can find more information on this.

In C++ how can I use a template function as the 3rd parameter in std::for_each?

I am trying to use std::for_each to output the contents of vectors, which may contain different types. So I wrote a generic output function like so:
template<typename T> void output(const T& val)
{
cout << val << endl;
}
which I would like to use with:
std::for_each(vec_out.begin(), vec_out.end(), output);
but the compiler complains with "could not deduce template argument" in the for_each statement. Also complains with "A function template cannot be an argument to another function template".
Is this not possible? I would have thought the compiler would know the type of vec_out (it's vector) and so should instantiate the function "output(const double& val)"?
If this doesn't work how can I get similar STL functionality without writing manual loops?
I am quite new to C++ and still learning the ropes :-)
Try:
std::for_each(vec_out.begin(), vec_out.end(), output<T>);
where vec_out is a container (vector) of type T.
Note: The for_each algorithm expects an unary functor for its last argument. See the link for an example using functors.
You have to pass an instantiation of the template. Something like output<int> if your vector is vector of integers.
For example:
template<typename T> void output(const T& val)
{
cout << val << endl;
}
void main(int argc,char *argv[])
{
std::vector<int> vec_out;
std::for_each(vec_out.begin(), vec_out.end(), output<int>);
}
I'd just like to add to the correct answers: the compiler can deduce the type if you wrap up your template function in a function object (aka functor):
struct OutputFunctor
{
template <typename T>
void operator()(const T& val) const { output(val); }
};
void test()
{
std::vector<int> ints;
std::vector<float> floats;
std::for_each(ints.begin(), ints.end(), OutputFunctor());
std::for_each(floats.begin(), floats.end(), OutputFunctor());
}