Problem
I am trying to make a function which searches for a type in a parameter pack, then creates a lambda which invokes another function with that type as a template parameter e.g.:
auto fn = findType<MyType, SomeType, OtherType>("OtherType");
fn(otherFn) == otherFn<OtherType>();
I would like to write something like this:
template<class T, class ...Ts>
auto findType(const std::string& name) {
if (refl::is_reflectable<T>() && refl::reflect<T>().name == name) {
return []<class Fn>(Fn fn) {
fn<T>();
};
}
return findType<Ts...>(name);
}
However, C++ doesn't seem to recognise that fn could be parameterised with template types.
I am using gcc10 and C++20, so if possible, I can also use concepts.
I believe the problem can be summed up as: How can I pass a template-parameterised function into another function?
template<class C>
void fn() {}
template<class Fn, class Arg>
void mainFn(Fn fn) {
fn<Arg>(); // ???
}
Attempted searches
I had looked at template template parameters, but that seems to be only for templating types, not function calls.
I had also looked at C++ concepts, but std::invokable doesn't take in template parameters and requirements also don't seem to allow for such expressions:
return []<class Fn>(Fn fn) requires requires { fn<T>(); } {
Function parameters are variables. Not variable templates; just regular old variables. And a non-template variable cannot be given template parameters.
You cannot pass a function template anywhere. You can only pass a particular instantiation of a function template. The closest you can get to what you want is to pass a type that has a templated operator() overload, but unless you can provide the template parameters through deduction, the only way to invoke it is via fn.operator()<TemplateArguments>(params). So you may as well have given it a meaningful name.
The closest I can comeup with is to wrap the function template within class wrapper to achieve similar effect (Live):
#include <iostream>
using namespace std;
struct Fn
{
template <class Arg>
static void fn() {cout << "Fn::fn()\n";}
};
struct Gn
{
template <class Arg>
static void fn() { cout << "Gn::fn()\n"; }
};
template<class Arg, class F>
void mainFn(F dummy) {
F::template fn<Arg>();
}
int main()
{
mainFn<int>(Fn{});
mainFn<int>(Gn{});
}
outputs
Fn::fn()
Gn::fn()
I just wanted to put the closest I have gotten to what I wanted for others who may have special cases where this is possible.
As Nicol Bolas has already said, it is only possible through type deduction. So, if you have control over the function you receive, you can actually use that:
template<class C>
void fn(C* ignore) {}
template<class Fn, class Arg>
void mainFn(Fn fn) {
Arg* ignore = nullptr;
fn(ignore);
}
This removes the type parameter and makes use of type deduction to find the type.
In my case, this is insufficient as RedFog has mentioned that my findType function actually returns different types on the seemingly same call.
For C++, a practical way to go about passing a function to another function would be as follows:
#include <iostream>
#include <functional>
// To build and run the code
// g++ -std=c++20 -O3 -Wall -Werror -Wshadow -pedantic file.cpp -o file && ./file
double add5(double input_value) {
return input_value + 5;
}
template<typename T>
T add2(T input_value) {
return input_value + (T)2;
}
// std::function<double(double)> func
// return type ----^ ^---------------\
// list of `func` input argument types ---/
double func(double input_value, std::function<double(double)> func) {
return func(input_value);
}
int main() {
double value1 = 10.75;
double value2 = add2(value1);
std::cout << "Value1: " << value1 << std::endl;
std::cout << "Value2: " << value2 << std::endl;
// Add 5 to value2 by passing value2 and function 'add5' to function 'func'
double value3 = func(value2, &add5);
std::cout << "Value3: " << value3 << std::endl;
}
If you compile and run this code, the output should look like
Value1: 10.75
Value2: 12.75
Value3: 17.75
However, if you try to pass the template function (add2) to func, you will receive something along the lines of error: no matching function for call to 'func'. C++ does not allow you to pass template functions to other functions, BUT C++ does allow you to pass specific instances of template functions to other functions. If you replace
double value3 = func(value2, &add5);
with
double value3 = func(value2, &add2<double>);
at the bottom of main(), this will achieve the desired result.
Value1: 10.75
Value2: 12.75
Value3: 14.75
Unfortunately C++ does not allow you to pass a generalized template function to other functions at the moment.
Related
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.)
I am attempting to recreate the Observer pattern where I can perfectly forward parameters to a given member function of the observers.
If I attempt to pass the address of a member function which has multiple overrides, it cannot deduce the correct member function based on the arguments.
#include <iostream>
#include <vector>
#include <algorithm>
template<typename Class>
struct observer_list
{
template<typename Ret, typename... Args, typename... UArgs>
void call(Ret (Class::*func)(Args...), UArgs&&... args)
{
for (auto obj : _observers)
{
(obj->*func)(std::forward<UArgs>(args)...);
}
}
std::vector<Class*> _observers;
};
struct foo
{
void func(const std::string& s)
{
std::cout << this << ": " << s << std::endl;
}
void func(const double d)
{
std::cout << this << ": " << d << std::endl;
}
};
int main()
{
observer_list<foo> l;
foo f1, f2;
l._observers = { &f1, &f2 };
l.call(&foo::func, "hello");
l.call(&foo::func, 0.5);
return 0;
}
This fails to compile with template argument deduction/substitution failed.
Note that I had Args... and UArgs... because I need to be able to pass parameters which are not necessarily the same type asthe type of the function signature, but are convertible to said type.
I was thinking I could use a std::enable_if<std::is_convertible<Args, UArgs>> call to disambiguate, but I don't believe I can do this with a variadic template parameter pack?
How can I get the template argument deduction to work here?
The issue is here:
l.call(&foo::func, "hello");
l.call(&foo::func, 0.5);
For both lines, the compiler doesn't know which foo::func you are referring to. Hence, you have to disambiguate yourself by providing the type information that is missing (i.e., the type of foo:func) through casts:
l.call(static_cast<void (foo::*)(const std::string&)>(&foo::func), "hello");
l.call(static_cast<void (foo::*)(const double )>(&foo::func), 0.5);
Alternatively, you can provide the template arguments that the compiler cannot deduce and that define the type of func:
l.call<void, const std::string&>(&foo::func, "hello");
l.call<void, double >(&foo::func, 0.5);
Notice that you have to use double and not const double above. The reason is that generally double and const double are two different types. However, there's one situation where double and const double are considered as if they were the same type: as function arguments. For instance,
void bar(const double);
void bar(double);
are not two different overloads but are actually the same function.
The following template definition
template <typename Func, typename ReturnType, typename... Arguments>
class Command
{
public:
Command(Func f) : m_func(f) { }
ReturnType operator()(Arguments... funcArgs) { return m_func(funcArgs...); }
private:
Func m_func;
};
gives an error message with gcc 4.7.3 (error: field 'Command::m_func' invalidly declared function type) when instantiated with the following test code:
void testFunction(int i, double d)
{
std::cout << "TestFunctor::operator()(" << i << ", " << d << ") called." << std::endl;
}
int main()
{
void (&fRef)(int, double) = TestFunction;
Command<void(int, double), void, int, double> testCommand(fRef);
}
The error message also occurs if I pass TestFunction without the address-of operator into the testCommand constructor, but disappears if I pass either an explicitly named function pointer or use the address-of operator to pass the parameter. I'm under the impression that this code should work given Chapter 5 of Modern C++ Design.
What is the reasoning behind not being able to store a reference to a function, but function pointers work fine? Are there any workarounds that would allow this to compile without losing support for being able to pass functors as arguments to Command's constructor as well?
Changing one line could fix it:
Command<void(*)(int, double), void, int, double> testCommand(fRef);
The difference is, you're passing a function pointer now, instead of a function type. (Functions aren't copyable, but pointers are).
The reference fRef decays to a function pointer when you pass it.
I wouldn't suggest using std::function if performance mattered.
See it live on Coliru
Note that with a little rewriting, you can make it all work much nicer:
int main()
{
auto command = make_command(testFunction);
command(1, 3.14);
}
To do this, I'd suggest changing the Command template to be:
template <typename Func>
class Command
{
Func m_func;
public:
Command(Func f) : m_func(f) { }
template <typename... A> auto operator()(A... args) const
-> decltype(m_func(args...))
{ return m_func(args...); }
};
And now you can have type-deduction on the Func template parameter by having a factory function:
template <typename Func> Command<Func> make_command(Func f)
{
return Command<Func>(f);
}
See this approach live on Coliru too. Of course, the output it the same:
TestFunctor::operator()(1, 3.14) called.
C++11 offers an std::function template. You don't have to mess with function pointers.
You can pass those by reference, copy them, move them and they can even be used to store lambdas:
std::function<void()> func = []() { std::cout << "Hi" << std::endl; };
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) << ' '; });
}
I have three template arguments to a function and am having troubles with (I think) the compiler deducing which template argument is which.
The template function is:
#include <structures/partition.h>
#include <vector>
namespace cliques
{
template <typename P, typename T, typename QF>
P find_optimal_partition_louvain(cliques::Graph<T> &my_graph,
QF quality_function)
{
P dummy;
}
}
And when I try to call it with
cliques::find_optimal_partition_louvain<cliques::DisjointSetForest>(my_new_graph, cliques::find_linearised_stability(current_markov_time));
Where template argument P should correspond to cliques::DisjointSetForest, and the normal function arguments are a templated class and a function object.
This fails with
error: no matching function for call to
find_optimal_partition_louvain(cliques::Graph<lemon::ListGraph>&,
cliques::find_linearised_stability)
However if I use a builtin type such as an int or a float for the P parameter everything compiles fine.
e.g.
cliques::find_optimal_partition_louvain<int>(my_new_graph, cliques::find_linearised_stability(current_markov_time));
So my question is what am I doing wrong here, how can I use a better inform the compiler which parameter is which, or am I completely off track?
I hate to answer my own question but problem was that cliques::DisjointSubsetForest is actually a templated class so
cliques::find_optimal_partition_louvain<cliques::DisjointSetForest<int> >(my_new_graph, cliques::find_linearised_stability(current_markov_time));
works
"error: no matching function for call to ‘find_optimal_partition_louvain(cliques::Graph&, cliques::find_linearised_stability)"
It would seem that your compiler thinks that cliques::Graph is not a template.
I have tried to reproduce the error on a simple example, but I failed to do so (on gcc).
It looks as though the compiler does figure out that find_optimal_partition_louvain is a function template. I suggest trying the following:
cliques::template find_optimal_partition_louvain<cliques::DisjointSetForest>(my_new_graph, cliques::find_linearised_stability(current_markov_time));
Otherwise, you might want to verify if the following simple example compiles fine on your compiler (because it should!):
#include <iostream>
template <class G>
struct Bar { };
namespace Foo {
template <class A, class B, class C>
A some_function(Bar<B>&, C aFunc) {
aFunc();
return A();
};
};
struct HWPrinter {
HWPrinter() { std::cout << "Hello World!" << std::endl; };
};
struct IntPrinter {
int value;
IntPrinter(int aValue) : value(aValue) { };
void operator() () { std::cout << "The integer is: " << value << std::endl; };
};
int main() {
Bar<HWPrinter> ab;
Foo::some_function<HWPrinter>(ab,IntPrinter(42));
return 0;
};