Template type inference using std::views - c++

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.

Related

How can I call a template function in another template function

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.

C++ Operator overloading with templated types are giving me errors

I have been struggling with how to make a minimal verifiable example of this but I cannot think of how to do it. I have two Expected Types that I am trying to add together. The expected can be a data type such as int, double, etc. Or it can be an exception. In theory, I should be able to add the data type with an exception and it will be able to run the program just fine, when I ask for the value. It should return the exception without crashing the program.
Whenever I try to run this program I get hundreds of lines of error messages that I don't even know where to begin, the one error I see is no matching function for call to 'operator+(double&,double&) I do not know if this is correct either, because I want to add two Expected's together, I do not want to add the types themselves. In the end, I want to add an Expected, and get returned and Expected.
I am really stuck here, I was told that my apply function has been implemented incorrectly but I honestly cannot see why that is the case. What am I doing wrong?
#include <stdexcept>
#include <exception>
#include <functional>
#include <variant>
template<typename T>
class Expected
{
public:
Expected(T t) : state(t), valid(true){}
Expected(std::exception_ptr e) : state(e), valid(false){}
Expected(std::exception e) : state(std::make_exception_ptr(e)), valid(false){}
T value() const
{
if(valid) return std::get<T>(state);
std::rethrow_exception(std::get<std::exception_ptr>(state));
}
bool isValid()
{
if(valid) return true;
return false;
}
template<typename U>
Expected<U> apply(std::function<U(T)> f)
{
if(!valid) return std::get<std::exception_ptr>(state);
try
{
return f(std::get<T>(state));
}
catch(...)
{
return std::current_exception();
}
}
private:
std::variant<T, std::exception_ptr> state;
bool valid;
};
template<typename T>
std::ostream& operator<< (std::ostream& o, Expected<T> e)
{
try
{
o << e.value();
}
catch(std::exception &a)
{
o << a.what();
}
catch(...)
{
o << "Unexpected Error";
}
return o;
}
template<typename T, typename V>
auto operator+(Expected<T> t, Expected<V> v)
{
return t.apply([&](T myT){return operator+(myT,v);});
}
template<typename T, typename V>
auto operator+(Expected<T> t, V v)
{
return t.apply([&](T myT){return operator+(myT,v);});
}
template<typename T, typename V>
auto operator+(V v, Expected<T> t)
{
return t.apply([&](T myT){return operator+(v,myT);});
}
int main()
{
Expected<int> a = 1;
Expected<int> b = 2;
std::cout << a + b << std::endl;
}
Here's a reduced example of the first problem:
int main() {
operator+(1, 2); // error
}
You cannot call builtin operators by name. You can only call them by operator. Moreover, just using the operator is easier to read anyway - so just do that. Use +. (Also, in one part of your code, you're using op instead of what presumably should be operator+).
Here's a reduced example of the second problem:
template <typename T>
struct X {
template<typename U>
U apply(std::function<U(T)> f);
};
int main() {
X<int>{}.apply([](int ){return 2.0;}); // error
}
Basically, deducing a std::function is almost always wrong. This lambda is not a std::function, it is not a std::function<double(int)>. What you want to do, almost always, is deduce an arbitrary callable, and then use a metafunction to determine the result:
template <typename T>
struct X {
template <typename F, typename U = std::invoke_result_t<F&, T>>
U apply(F f);
};
First off: In general, if you're getting too many errors, simplify your test case by leaving out some code until you're down to one problem in the code (that could still be reported as multiple errors, though). Either you will understand that error, or you will have a concrete thing to ask about. In this case, this would mean starting with just one overload of operator +, with no operator <<.
Now to your code: there are multiple issues. First off, why are you calling operator+ (a, b) instead of the more logical a + b? This actually causes the error you've mentioned explicitly in the question, because there's not operator+ function taking two doubles: the built-in operator + is not a function and cannot be called as such.
The second problem is that the template parameter U of apply cannot be deduced from lambda expressions, because the type of a lambda expression is not std::function. Which means you have to provide an explicit template argument for it:
return t.template apply<decltype(std::declval<T>() + v)>([&](T myT){return myT + v;});
This change needs to happen in all 3 overloads of operator + (I assume the unknown op in the 3rd overload is a weird typo and should actually also be calling +).
Notice the need for the template keyword before apply, because it's used in a dependent context.
Note that Barry's answer provides a better approach to this by getting rid of std::function altogether.
Finally, you're missing #include <iostream>.
With all these changes in place, your code [works].

Containers for different signature functions

I'm trying to programming in C++ a framework where the user can indicates a set of functions inside its program where he wants to apply a memoization strategy.
So let's suppose that we have 5 functions in our program f1...f5 and we want to avoid the (expensive) re-computation for the functions f1 and f3 if we already called them with the same input. Notice that each function can have different return and argument types.
I found this solution for the problem, but you can use only double and int.
MY SOLUTION
Ok I wrote this solution for my problem, but I don't know if it's efficient, typesafe or can be written in any more elegant way.
template <typename ReturnType, typename... Args>
function<ReturnType(Args...)> memoize(function<ReturnType(Args...)> func)
{
return ([=](Args... args) mutable {
static map<tuple<Args...>, ReturnType> cache;
tuple<Args...> t(args...);
auto result = cache.insert(make_pair(t, ReturnType{}));
if (result.second) {
// insertion succeeded so the value wasn't cached already
result.first->second = func(args...);
}
return result.first->second;
});
}
struct MultiMemoizator
{
map<string, boost::any> multiCache;
template <typename ReturnType, typename... Args>
void addFunction(string name, function < ReturnType(Args...)> func) {
function < ReturnType(Args...)> cachedFunc = memoize(func);
boost::any anyCachedFunc = cachedFunc;
auto result = multiCache.insert(pair<string, boost::any>(name,anyCachedFunc));
if (!result.second)
cout << "ERROR: key " + name + " was already inserted" << endl;
}
template <typename ReturnType, typename... Args>
ReturnType callFunction(string name, Args... args) {
auto it = multiCache.find(name);
if (it == multiCache.end())
throw KeyNotFound(name);
boost::any anyCachedFunc = it->second;
function < ReturnType(Args...)> cachedFunc = boost::any_cast<function<ReturnType(Args...)>> (anyCachedFunc);
return cachedFunc(args...);
}
};
And this is a possible main:
int main()
{
function<int(int)> intFun = [](int i) {return ++i; };
function<string(string)> stringFun = [](string s) {
return "Hello "+s;
};
MultiMemoizator mem;
mem.addFunction("intFun",intFun);
mem.addFunction("stringFun", stringFun);
try
{
cout << mem.callFunction<int, int>("intFun", 1)<<endl;//print 2
cout << mem.callFunction<string, string>("stringFun", " World!") << endl;//print Hello World!
cout << mem.callFunction<string, string>("TrumpIsADickHead", " World!") << endl;//KeyNotFound thrown
}
catch (boost::bad_any_cast e)
{
cout << "Bad function calling: "<<e.what()<<endl;
return 1;
}
catch (KeyNotFound e)
{
cout << e.what()<<endl;
return 1;
}
}
How about something like this:
template <typename result_t, typename... args_t>
class Memoizer
{
public:
typedef result_t (*function_t)(args_t...);
Memoizer(function_t func) : m_func(func) {}
result_t operator() (args_t... args)
{
auto args_tuple = make_tuple(args...);
auto it = m_results.find(args_tuple);
if (it != m_results.end())
return it->second;
result_t result = m_func(args...);
m_results.insert(make_pair(args_tuple, result));
return result;
}
protected:
function_t m_func;
map<tuple<args_t...>, result_t> m_results;
};
Usage is like this:
// could create make_memoizer like make_tuple to eliminate the template arguments
Memoizer<double, double> memo(fabs);
cout << memo(-123.456);
cout << memo(-123.456); // not recomputed
It's pretty hard to guess at how you're planning to use the functions, with or without memoisation, but for the container-of-various-function<>s aspect you just need a common base class:
#include <iostream>
#include <vector>
#include <functional>
struct Any_Function
{
virtual ~Any_Function() {}
};
template <typename Ret, typename... Args>
struct Function : Any_Function, std::function<Ret(Args...)>
{
template <typename T>
Function(T& f)
: std::function<Ret(Args...)>(f)
{ }
};
int main()
{
std::vector<Any_Function*> fun_vect;
auto* p = new Function<int, double, double, int> { [](double i, double j, int z) {
return int(i + j + z);
} };
fun_vect.push_back(p);
}
The problem with this is how to make it type-safe. Look at this code:
MultiMemoizator mm;
std::string name = "identity";
mm.addFunction(name, identity);
auto result = mm.callFunction(name, 1);
Is the last line correct? Does callFunction have the right number of parameters with the right types? And what is the return type?
The compiler has no way to know that: it has no way of understanding that name is "identity" and even if it did, no way to associate that with the type of the function. And this is not specific to C++, any statically-typed language is going to have the same problem.
One solution (which is basically the one given in Tony D's answer) is to tell the compiler the function signature when you call the function. And if you say it wrong, a runtime error occurs. That could look something like this (you only need to explicitly specify the return type, since the number and type of parameters is inferred):
auto result = mm.callFunction<int>(name, 1);
But this is inelegant and error-prone.
Depending on your exact requirements, what might work better is to use "smart" keys, instead of strings: the key has the function signature embedded in its type, so you don't have to worry about specifying it correctly. That could look something like:
Key<int(int)> identityKey;
mm.addFunction(identityKey, identity);
auto result = mm.callFunction(identityKey, 1);
This way, the types are checked at compile time (both for addFunction and callFunction), which should give you exactly what you want.
I haven't actually implemented this in C++, but I don't see any reason why it should be hard or impossible. Especially since doing something very similar in C# is simple.
you can use vector of functions with signature like void someFunction(void *r, ...) where r is a pointer to result and ... is variadic argument list. Warning: unpacking argument list is really inconvenient and looks more like a hack.
At first glance, how about defining a type that has template arguments that differ for each function, i.e.:
template <class RetType, class ArgType>
class AbstractFunction {
//etc.
}
have the AbstractFunction take a function pointer to the functions f1-f5 with template specializations different for each function. You can then have a generic run_memoized() function, either as a member function of AbstractFunction or a templated function that takes an AbstractFunction as an argument and maintains a memo as it runs it.
The hardest part will be if the functions f1-f5 have more than one argument, in which case you'll need to do some funky things with arglists as template parameters but I think C++14 has some features that might make this possible. An alternative is to rewrite f1-f5 so that they all take a single struct as an argument rather than multiple arguments.
EDIT: Having seen your problem 1, the problem you're running into is that you want to have a data structure whose values are memoized functions, each of which could have different arguments.
I, personally, would solve this just by making the data structure use void* to represent the individual memoized functions, and then in the callFunction() method use an unsafe type cast from void* to the templated MemoizedFunction type you need (you may need to allocate MemoizedFunctions with the "new" operator so that you can convert them to and from void*s.)
If the lack of type safety here irks you, good for you, in that case it may be a reasonable option just to make hand-written helper methods for each of f1-f5 and have callFunction() dispatch one of those functions based on the input string. This will let you use compile-time type checking.
EDIT #2: If you are going to use this approach, you need to change the API for callFunction() slightly so that callFunction has template args matching the return and argument types of the function, for example:
int result = callFunction<int, arglist(double, float)>("double_and_float_to_int", 3.5, 4);
and if the user of this API ever types the argument type or return types incorrectly when using callFunction... pray for their soul because things will explode in very ugly ways.
EDIT #3: You can to some extent do the type checking you need at runtime using std::type_info and storing the typeid() of the argument type and return type in your MemoizedFunction so that you can check whether the template arguments in callFunction() are correct before calling - so you can prevent the explosion above. But this will add a bit of overhead every time you call the function (you could wrap this in a IF_DEBUG_MODE macro to only add this overhead during testing and not in production.)

How to call a function using an argument supplied from the template function

EDIT: Just to clarify "t" is successfully called when casted. The compiler knows and does state that it is a function pointer that takes an argument of type int. I supply a null int pointer to break the loop because it is calling itself recursively. It may just be a bug in the compiler.
I am trying to call a function from a template function argument.
I would assume that it would be possible to call the function without explicit casting but that does not seem to be the case. Using VC2013.
template<typename T>
void func(T t)
{
printf("calling func...\n");
if (t)
{
((void(__cdecl*)(int))t)((int)nullptr); // explicit casting is successful
t ((int)nullptr); // compile error: ``term does not evaluate to a function taking 1 arguments``
}
}
void main()
{
auto pe = func < int > ;
auto pf = func < void(__cdecl*)(int) >;
pf(pe);
}
You have the error for func<int> which becomes:
void func(int t)
{
printf("calling func...\n");
if (t)
{
((void(__cdecl*)(int))t)((int)nullptr); // bad casting
t ((int)nullptr); // compile error: int is not a callable object
}
}
When t is an int, of course you can't treat it like a function. You'll have to specialize the template for ints or use a different function. Also, please forget that there are C-style casts, they only serve to shoot yourself into the foot.
I don't understand what do you want exactly. But maybe something like this ?:
#include <iostream>
#include <type_traits>
template<typename T>
void call_helper(T value, std::true_type) // value is function
{
std::cout << "Function" << std::endl;
value(0);
}
template<typename T>
void call_helper(T value, std::false_type) // value is NOT function
{
std::cout << "Not function" << std::endl;
std::cout << value << std::endl;
}
template<typename T>
void call(T value)
{
call_helper(value, std::is_function<typename std::remove_pointer<T>::type>());
}
int main()
{
void (*f)(int) = call<int>;
call(f);
}
live example: http://rextester.com/DIYYZ43213

A problem with higher order functions and lambdas in C++0x

I have a program where I must print many STL vectors on the screen after doing some calculation on each component. So I tried to create a function like this:
template <typename a>
void printWith(vector<a> foo, a func(a)){
for_each(foo.begin(), foo.end(), [func](a x){cout << func(x) << " "; });
}
And then use it like this:
int main(){
vector<int> foo(4,0);
printWith(foo, [](int x) {return x + 1;});
return 0;
}
Unfortunately, I'm having a compiling error about the type of the lambda expression I've put inside the printWith call:
g++ -std=gnu++0x -Wall -c vectest.cpp -o vectest.o
vectest.cpp: In function ‘int main()’:
vectest.cpp:16:41: error: no matching function for call to ‘printWith(std::vector<int>&, main()::<lambda(int)>)’
vectest.cpp:10:6: note: candidate is: void printWith()
make: *** [vectest.o] Error 1
Of course, if I do:
int sumOne(int x) {return x+1;}
then printWith(foo, sumOne); works as intended. I thought the type of a lambda expression would be the type of a function with the inferred return type. I also though that I could fit a lambda anywhere I could fit a normal function. How do I make this work?
The following works for me:
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
template <typename a, typename F>
void printWith(vector<a> foo, F f){
for_each(foo.begin(), foo.end(), [&](a x){cout << f(x) << " "; });
}
int main(){
vector<int> foo = {1,2,3,4,5};
printWith(foo, [](int x) {return x + 1;});
std::cout << '\n';
return 0;
}
Testing:
$ g++-4.5 -std=gnu++0x -Wall test.cpp
$ ./a.out
2 3 4 5 6
Alternatively, you can exploit the fact that closure types with no lambda-capture can be implicitly converted to function pointers. This is closer to your original code and also cuts down on the number of instantiations of the function template (in the original solution you get a new instantiation every time you use the function template with a different function object type; note though that it doesn't matter much in this specific case since the printWith function is very short and most probably will be always inlined):
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
template <typename a, typename b>
void printWith(const vector<a>& foo, b f(a)){
for_each(foo.begin(), foo.end(), [=](a x){cout << f(x) << " "; });
}
int main(){
vector<int> foo = {1,2,3,4,5};
printWith<int, int>(foo, [](int x) {return x + 1;});
std::cout << '\n';
return 0;
}
Unfortunately, implicit conversion doesn't play very well with template argument deduction: as you can see, I had to specify template arguments in the call to printWith.
Another alternative is to use std::function. This also helps to minimize the number of template instantiations and works even for lambda expressions with lambda-capture, but has the same problems with template argument deduction:
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
using namespace std;
template <typename a, typename b>
void printWith(const vector<a>& foo, std::function<b(a)> f){
for_each(foo.begin(), foo.end(), [&](a x){cout << f(x) << " "; });
}
int main(){
vector<int> foo = {1,2,3,4,5};
int y = 1;
printWith<int, int>(foo, [&](int x) { return x + y; });
std::cout << '\n';
return 0;
}
The reason that you're having a problem is because you're trying to use a function. Free functions have a specific representation (as a function pointer) which is not interchangable with function objects of any kind. Function pointers (which is basically what you have here) should be avoided. You need to take a function object directly with it's type specified by template.
template <typename a, typename Func>
void printWith(vector<a> foo, Func func){
for_each(foo.begin(), foo.end(), [&](a x){cout << func(x) << " "; });
}
Alternatively, take a polymorphic function object such as std::function.
template<typename a>
void printWith(vector<a> foo, std::function<string(const a&)> func) {
for_each(foo.begin(), foo.end(), [&](a x) { cout << func(x) << " "; });
}
void printWith(vector<a> foo, b func(a)){
This is wrong, you can't do that and that makes the compiler not taking account of this code as it's not valid.
You have two ways to fix this :
1) don't ask for a parameter type, just ask for a functor:
void printWith(vector<a> foo, b func ){ // keep the rest of the code the same
The rest of your function will not compile if func don't take a a as parameter anyway.
2) force the functor type:
template <typename a>
void printWith(vector<a> foo, std::function< void (a) > func ){
Then it's like if you were using a function pointer. No (or less) compile-time optimization, but at least you enforce the functor signature. See std::function or boost::function for details.
The reason this doesn't work is that you're mixing template argument deduction with implicit conversions. If you get rid of deduction it works:
printWith<int>(foo, [](int x) {return x + 1;});
However, it would be better (inside printWith) to let func's type be another template parameter, as others recommend.
If on the other hand you really want to add constraints to this type there are better ways to do it using SFINAE (for soft errors) or static_assert (for hard errors).
For instance:
// A constraints metafunction
template<typename T, typename Element>
struct is_element_printer
: std::is_convertible<T, Element (*)(Element)>
{};
Here, is_element_printer<T, Element>::value is true iff T implicitly converts to Element (*)(Element). I'm only using this for illustrative purposes and I cannot recommend it for real use: there are plenty of things that could qualify as an 'element printer' in a lot of situations that are not function pointers. I'm only doing this because std::is_convertible is readily available from <type_traits> and there is no other more obvious test available. You should write your own.
Then:
template<typename Container, typename Functor>
void
printWith(Container&& container, Functor&& functor)
{
// avoid repetition
typedef typename std::decay<Container>::type::value_type value_type;
// Check our constraints here
static_assert(
std::is_element_printer<
typename std::decay<Functor>::type,
value_type
>::value,
"Descriptive error message here"
);
// A range-for is possible instead
std::for_each(container.cbegin(), container.cend(), [&functor](value_type const& v)
{ std::cout << functor(v) << ' '; });
}