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);
Related
I want to apply certain functionality to some elements of a tuple based on a given condition or constraint of the types.
Below is a small dummy example where I want to call a callback function for all the elements in the tuple that holds an arithmetic type. In my current solution, I use std::apply and if constexpr on the type constraint as the condition to call the callback.
However, I assume this is iterating through all the elements of the tuple?
And now I am wondering if there is an alternative to do this. In my head, it should be possible to select the indices of the elements of interest at compile-time, because all the types are known and then apply the functionality only for the elements at those indices. But I don't know if this is possible, nor how to translate this to code.
#include <iostream>
#include <string>
#include <tuple>
#include <type_traits>
template <typename... Args>
struct Foo {
using my_tuple = std::tuple<Args...>;
template <typename Fn>
void CallForArithmetic(Fn&& fn) {
auto arithmetic_call = [&]<typename T>(const T& x) {
if constexpr (std::is_arithmetic_v<T>) {
fn(x);
}
};
std::apply([&](auto&&... arg) { (arithmetic_call(arg), ...); }, tuple_);
};
private:
my_tuple tuple_;
};
int main() {
Foo<int, std::string> foo{};
int calls = 0;
// will be called only once for int type
foo.CallForArithmetic(
[&calls](const auto& arg) { std::cout << calls++ << '\n'; });
}
It's really "as if" you are iterating over the full tuple. In general, the compiled program will only do that if it has to, or if all optimisations are disabled, to aid debugging. And indeed, starting from -O1 (gcc) or -O2 (clang), a slightly simplified version of your code compiles to "return 1;":
main:
mov eax, 1
ret
Note: msvc finds the same result, but generates a lot of extra clutter.
So, as Jarod42 suggested, you can definitely expect your compiler to figure this out, and go with the solution that is easiest for you as a human. And if you're not sure, Compiler Explorer is a great tool for questions like yours.
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.
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.
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.
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());
}