My colleague provided me with a "small quiz", that he made his students solve once. It seems that my feeble mind is just unable to comprehend all the beauty of the modern C++ capabilities.
Subj:
Implementing a join function, accepting arbitrary functors and returning another functor, which behaves as any of them. Ex.:
{
auto result = std::visit(custom::join(
[](std::string const& s) { return "it's a string"; },
[](std::pair<int, int> const& p) { return "it's a pair"; }
), var);
assert(result == "it's a string");
var = std::make_pair(10, 20);
auto lvalue_lambda = [](std::string const& s) { return "it's a string"; };
result = std::visit(custom::join(
lvalue_lambda,
[](std::pair<int, int> const& p) { return "it's a pair"; }
), var);
assert(result == "it's a pair");
}
Okay, after a bit of thinking I got the idea, that std::variant means "one of the listed" as far as it is a "type-safe union", so I'll need a tuple. Tried something like that:
namespace custom
{
template<typename ...Functors>
class ResultFunctor
{
public:
ResultFunctor(Functors&&... funcs)
: m_funcs(std::make_tuple(std::move(funcs)...))
{}
template<typename ...Params>
auto operator()(Params... params) // that's where I got stuck
{
// return std::get<void(Params...)>(m_funcs)(params...); // No, the return type spoils this idea
return std::get<0>(m_funcs)(params...); // Now I need to choose the correct functor
}
private:
std::tuple<Functors...> m_funcs;
};
template<typename ...Functors>
ResultFunctor<Functors...> join(Functors&&... funcs)
{
return ResultFunctor(std::move(funcs)...);
}
}
If it were only for functors with void return type, I'd easily get the desired element of tuple. But there seems to be no way to determine it, return type cannot be deduced from given parameters (obviously).
Another idea was to use some SFINAE trick to choose the correct operator()() version, but this way or another I'll have to "run through" all the tuple item (which is nasty, but still can be googled) and then check if that item is suitable, based on the given parameters pack.
Well, that's where I took a pause to think it over thoroughly. If anyone (who deals better with all that variadic stuff) would have any ideas, I'd be really grateful.
This has a really simple solution that doesn't involve SFINAE or template metaprogramming (just regular templates).
The first step is to write a functor which represents the joint overload set. This is easy to achieve with inheritance, and because all the functors used as inputs must have different types, we don't have to do anything fancy.
// This represents overload set
template<class F1, class F2>
struct Joint : public F1, public F2 {
using F1::operator();
using F2::operator();
};
For user convenience, we can add a deduction guide:
template<class F1, class F2>
Joint(F1, F2) -> Joint<F1, F2>;
Because Joint is an aggregate type in C++17 and above, we don't have to provide a constructor because we can use aggregate initialization:
// This code magically works
auto result = std::visit(Joint{
[](std::string const& s) { return "it's a string"; },
[](std::pair<int, int> const& p) { return "it's a pair"; }
}, var);
Writing a custom::join function is equally simple:
template<class F1, class F2>
auto join(F1&& f1, F2&& f2) {
return Joint { std::forward<F1>(f1), std::forward<F2>(f2) };
}
Now that we have the base case, we can generalize it pretty easily:
template<class F, class F2, class... Fs>
auto join(F&& f, F2&& f2, Fs&&... fs) {
return Joint{
std::forward<F>(f),
join(std::forward<F2>(f2), std::forward<Fs>(fs)...)
};
}
Addressing potential criticisms
Why not define a constructor for Joint? Aggregate initialization is the most efficient form of initialization, because when you don't define a constructor the compiler is capable of assigning values in-place without having to copy or move them.
Why use multiple inheritance? If we rely on SFINAE, that increases compiletimes, increases code complexity, and it doesn't work as expected in some cases. With SFINAE, you have to check each member of the overload set to see if it's a fit. In some cases, due to implicit conversion, a worse overload is chosen because it was a match.
By using inheritance, we can use the languages' built-in pattern-matching for function calls.
Why add deduction guides? They make the code cleaner, and in this case they work exactly as expected: arguments are stored by value
namespace custom {
template<class...Fs>
struct overloaded : Fs... {
using Fs::operator()...;
};
template<class...Fs>
overloaded(Fs...)->overloaded<Fs...>;
template<class F>
F&& as_obj( F&& f ){ return std::forward<F>(f); }
template<class R, class...Args>
auto as_obj( R(*f)(Args...) {
struct helper {
R(*f)(Args...);
R operator()(Args...args) const { return f(std::forward<Args>(args)...); }
};
return helper{f};
}
template<class...Fs>
auto join( Fs&&...fs ){
return overloaded{as_obj(std::forward<Fs>(fs))...};
}
}
I added as a bonus support for non-overloaded function pointers.
Related
note: this question was briefly marked as a duplicate of this, but it is not an exact duplicate since I am asking about std::optionals specifically. Still a good question to read if you care about general case.
Assume I have nested optionals, something like this(dumb toy example):
struct Person{
const std::string first_name;
const std::optional<std::string> middle_name;
const std::string last_name;
};
struct Form{
std::optional<Person> person;
};
and this spammy function:
void PrintMiddleName(const std::optional<Form> form){
if (form.has_value() && form->person.has_value() && form->person->middle_name.has_value()) {
std::cout << *(*(*form).person).middle_name << std::endl;
} else {
std::cout << "<none>" << std::endl;
}
}
What would be the best way to flatten this optional check?
I have made something like this, it is not variadic, but I do not care that much about that(I can add one more level(overload with membr3) if really necessary, and everything beyond that is terrible code anyway).
template<typename T, typename M>
auto flatten_opt(const std::optional<T> opt, M membr){
if (opt.has_value() && (opt.value().*membr).has_value()){
return std::optional{*((*opt).*membr)};
}
return decltype(std::optional{*((*opt).*membr)}){};
}
template<typename T, typename M1, typename M2>
auto ret_val_helper(){
// better code would use declval here since T might not be
// default constructible.
T t;
M1 m1;
M2 m2;
return ((t.*m1).value().*m2).value();
}
template<typename T, typename M1, typename M2>
std::optional<decltype(ret_val_helper<T, M1, M2>())> flatten_opt(const std::optional<T> opt, M1 membr1, M2 membr2){
if (opt.has_value() && (opt.value().*membr1).has_value()){
const auto& deref1 = *((*opt).*membr1);
if ((deref1.*membr2).has_value()) {
return std::optional{*(deref1.*membr2)};
}
}
return {};
}
void PrintMiddleName2(const std::optional<Form> form){
auto flat = flatten_opt(form, &Form::person, &Person::middle_name);
if (flat) {
std::cout << *flat;
}
else {
std::cout << "<none>" << std::endl;
}
}
godbolt
notes:
I do not want to switch away from std::optional to some better optional.
I do not care that much about perf, unless I return a pointer I must make copy(unless arg is temporary) since std::optional does not support references.
I do not care about flatten_has_value function(although it is useful), since if there is a way to nicely flatten the nested optionals there is also a way to write that function.
I know my code looks like it works, but it is quite ugly, so I am wondering if there is a nicer solution.
The operation you're looking for is called the monadic bind operation, and is sometimes spelled and_then (as it is in P0798 and Rust).
You're taking an optional<T> and a function T -> optional<U> and want to get back an optional<U>. In this case the function is a pointer to data member, but it really does behave as a function in this sense. &Form::person takes a Form and gives back an optional<Person>.
You should write this in a way that is agnostic to the kind of function. The fact that it's specifically a pointer to member data isn't really important here, and maybe tomorrow you'll want a pointer to member function or even a free function. So that's:
template <typename T,
typename F,
typename R = std::remove_cvref_t<std::invoke_result_t<F, T>>,
typename U = mp_first<R>>
requires SpecializationOf<R, std::optional>
constexpr auto and_then(optional<T> o, F f) -> optional<U>
{
if (o) {
return std::invoke(f, *o);
} else {
return std::nullopt;
}
}
This is one of the many kinds of function declarations that are just miserable to write in C++, even with concepts. I'll leave it as an exercise to properly add references into there. I choose to specifically write it as -> optional<U> rather than -> R because I think it's important for readability that you can see that it does, in fact, return some kind of optional.
Now, the question is how do we chain this to multiple functions. Haskell uses >>= for monadic bind, but in C++ that has the wrong association (o >>= f >>= g would evaluate f >>= g first and require parentheses). So the next closest chose of operator would be >> (which means something different in Haskell, but we're not Haskell, so it's okay). Or you could implement this borrowing the | model that Ranges does.
So we'd either end up syntactically with:
auto flat = form >> &Form::person >> &Person::middle_name;
or
auto flat = form | and_then(&Form::person)
| and_then(&Person::middle_name);
A different way to compose multiple monadic binds together is an operation that Haskell spells >=>, which is called Kleisli composition. In this case, it takes a function T -> optional<U> and a function U -> optional<V> and produces a function T -> optional<V>. This is something that is exceedingly annoying to write constraints for so I'm just going to skip it, and it would look something like this (using the Haskell operator spelling):
template <typename F, typename G>
constexpr auto operator>=>(F f, G g) {
return [=]<typename T>(T t){
using R1 = std::remove_cvref_t<std::invoke_result_t<F, T>>;
static_assert(SpecializationOf<R1, std::optional>);
using R2 = std:remove_cvref_t<std::invoke_result_t<G, mp_first<R1>>>;
static_assert(SpecializationOf<R2, std::optional>);
if (auto o = std::invoke(f, t)) {
return std::invoke(g, *o);
} else {
// can't return nullopt here, have to specify the type
return R2();
}
};
}
And then you could write (or at least you could if >=> were an operator you could use):
auto flat = form | and_then(&Form::person >=> &Person::middle_name);
Because the result of >=> is now a function that takes a Form and returns an optional<string>.
Let's look at what the optimal form of a flatten function would look like. By "optimal" in this case, I mean the smallest presentation.
Even in the optimal case, at the point of performing the flatten operation, you would need to provide:
The optional<T> object to flatten.
The flatten operation function name.
A list of names, in order, to be indirected from at each flattening step.
Your code is very close to optimal. The only issue is that each name in the "list of names" must contain the typename of the member you're accessing at that level, which is something that hypothetically could be computed using knowledge of T.
C++ has no mechanism to do any better than this. If you want to access a member of an object, you must provide the type of that object. If you want to indirectly do this, C++ allows member pointers, but getting such a pointer requires knowing the type of the object at the point when the member is extracted. Even offsetof gymnastics would require using the type name when you're getting the offset.
Reflection would allow for something better, as you could pass compile-time strings that static reflection could use to fetch member pointers from the type currently in use. But C++20 has no such feature.
You've got a lot of helper functions for something that is fundamentally a chainable operation. And C++ has things for chains: operators. So I'd probably (ab)use operator* for this.
For your specific case, all you need is
template<class class_t, class member_t>
std::optional<std::remove_cv_t<member_t>> operator*(
const std::optional<class_t>& opt,
const std::optional<member_t> class_t::*member)
{
if (opt.has_value()) return opt.value().*member;
else return {};
}
void PrintMiddleName2(const std::optional<Form> form){
auto middle = form * &Form::person * &Person::middle_name;
if (middle) {
std::cout << *middle;
}
else {
std::cout << "<none>" << std::endl;
}
}
But in reality you'd probably also want variants for non-optional members, getter methods, and arbitrary transforms, which I've listed here, though I'm not 100% certain they all compile properly.
//data member
template<class class_t, class member_t>
std::optional<std::remove_cv_t<member_t>> operator*(const std::optional<class_t>& opt, const std::optional<member_t> class_t::*member) {
if (opt.has_value()) return opt.value().*member;
else return {};
}
template<class class_t, class member_t>
std::optional<std::remove_cv_t<member_t>> operator*(const std::optional<class_t>& opt, const member_t class_t::*member) {
if (opt.has_value()) return {opt.value().*member};
else return {};
}
//member function
template<class class_t, class return_t>
std::optional<std::remove_cv_t<return_t>> operator*(const std::optional<class_t>& opt, std::optional<return_t>(class_t::*member)()) {
if (opt.has_value()) return opt.value().*member();
else return {};
}
template<class class_t, class return_t>
std::optional<std::remove_cv_t<return_t>> operator*(const std::optional<class_t>& opt, return_t(class_t::*member)()) {
if (opt.has_value()) return {opt.value().*member()};
else return {};
}
//arbitrary function
template<class class_t, class return_t, class arg_t>
std::optional<std::remove_cv_t<return_t>> operator*(const std::optional<class_t>& opt, std::optional<return_t>(*transform)(arg_t&&)) {
if (opt.has_value()) return transform(opt.value());
else return {};
}
template<class class_t, class return_t, class arg_t>
std::optional<std::remove_cv_t<return_t>> operator*(const std::optional<class_t>& opt, return_t(*transform)(arg_t&&)) {
if (opt.has_value()) return {transform(opt.value())};
else return {};
}
http://coliru.stacked-crooked.com/a/26aa7a62f38bbd89
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 have a higher order function map which is similar to STL for_each, and maps a std::function object over a vector of things.
template<class T, class U>
vector<U> map(function<U (T)> f, vector<T> xs) {
vector<U> ret;
for (auto &x: xs)
ret.push_back(f(x));
return ret;
}
Now, I want to have this higher order function take both objects of types function<int (const vector<T>&)> and function<int (vector<T>)>, as shown in the attached minimal example.
The problem is that function<int (const vector<T>&)> and function<int (vector<T>)> seem to be convertible to each other (see head and head2), but map won't take the const references version function<int (const vector<int>&)> (see Q1).
It is possible to tell map to accept the const reference version with explicit conversion (Q2), but this is rather cumbersome.
I was wondering if, in general, it is possible to write a function deref that removes the const reference from function<int (const vector<T>&)> and returns a function<int (vector<T>)>?
(If above is possible, then I won't have to write two identical overloads/implementations of map for const refs).
Thanks.
#include <vector>
#include <functional>
using namespace std;
template<class T, class U>
vector<U> map(function<U (T)> f, vector<T> xs) {
vector<U> ret;
for (auto &x: xs)
ret.push_back(f(x));
return ret;
}
int main() {
vector<vector<int>> m;
function<int (const vector<int>&)> head = [](const vector<int>& a) {return a[0];};
function<int (const vector<int>&)> head1 = [](vector<int> a) {return a[0];}; //conversion OK
function<int (vector<int>)> head2 = [](const vector<int>& a) {return a[0];}; //conversion OK
map(head2,m); //OK
map(head,m); //Q1: problem line, implicit conversion NOT OK
map(function<int (vector<int>)>(head),m); //Q2: explicit conversion OK
map(deref(head),m); //Q3: ??How-to, deref takes a std::function f and returns a function with const ref removed from its signature
return 0;
}
--- EDIT ---
I am particularly interested in a deref like function or a meta-function that can remove the const ref from the type signature of a std::function object, so that I can at least do Q2 automatically.
I know that, as #Brian and #Manu correctly pointed out, the use of std::function to specify types is not conventional, but I wonder what I asked above is even feasible. Personally, I think code with std::function has greater clarity, considering how generic function types Func<T1, T2, T3, ...,Tn, Tresult> are used in C#. This is if the cost of type erasure is tolerable.
I fully agree that c++ can infer return types and give an error message when type is wrong. Maybe it's just a matter of taste and I would prefer to spell it out when writing function signatures.
I understand why you are using std::function: You have to know the return type of the transformation to create the vector, right?
But consider a completely different approach. Given the metafunction std::result_of you could compute the result type of a function call, so just write:
template<typename F , typename CONTAINER , typename T = typename std::result_of<F(typename CONTAINER::value_type)>::type>
std::vector<T> map( F f , CONTAINER&& container )
{
std::vector<T> result;
for( auto& e : container )
result.emplace_back( f( e ) );
return result;
}
Advantages:
No abuse of std::function: Always think what std::function does (i.e. type erasure), don't use it as an universal function type.
Rely on duck typing instead of coupling on the types: Don't worry, if something was wrong it wouldn't compile neither.
Works for any Standard Library Container since we extracted the element type with the value_type trait, instead of using std::vector directly.
The code is much more clear and efficient, both because the reduction of std::function usage.
Regarding the question "Its possible to write a function that accepts lambdas of multiple signatures?"
Using std::function you could write something similar to Boost.OverloadedFunction in a couple of lines:
template<typename F , typename... Fs>
struct overloaded_function : public std_function<F> , public std_function<Fs>...
{
overloaded_function( F&& f , Fs&&... fs ) :
std_function<F>{ f },
std_function<Fs>{ fs }...
{}
};
Where std_function is a metafunction which given a function type F returns the std::function instance with the signature of F. I leave it as a game/challenge for the reader.
Thats all. Improve it with a make-like function:
template<typename F , typename... Fs>
overloaded_function<F,Fs...> make_overloaded_function( F&& f , Fs&&... fs )
{
return { std::forward<F>( f ) , std::forward<Fs>( fs )... };
}
And you are ready to go:
auto f = make_overloaded_function( [](){ return 1; } ,
[](int,int){ return 2; } ,
[](const char*){ return 3; } );
f(); //Returns 1
f(1,2); //Returns 2
f("hello"); //Returns 3
EDIT: "Thanks. But, what I am really looking for, is a meta-function that takes the signature of a callable, and removes the const refs from the signature."
Ok, let me try: The std::decay metafunction applies the decaying done when passing argumments by value to a given type. This includes removing cv qualifiers, removing references, etc. So a metafunction like yours could be something that takes a function signature type and applies decaying to all its argumments:
template<typename F>
struct function_decay;
template<typename R typename... ARGS>
struct function_decay<R(ARGS...)>
{
using type = R(typename std::decay<ARGS>::type...);
};
That should do the work.
I have written this because you explicitly asked for it in the comment, but I strongly encourage you to use the alternative I showed you initially, because it has many advantages compared to your way.
That said, I hope this answer helped to solve your problem.
The idiomatic solution is to simply allow map to take an arbitrary function-like type,
template<class T, class F>
auto map(F f, vector<T> xs) -> vector<typename result_of<F(T)>::type> {
vector<typename result_of<F(T)>::type> ret;
for (auto &x: xs)
ret.push_back(f(x));
return ret;
}
The main issue with this approach is that you get confusing error messages if F is not callable with arguments of type T, or if it returns something strange, like void.
(A secondary issue is that the first argument to map can't be an overloaded function; the compiler won't simply be able to pick the overload that takes an argument of type T.)
(You might also want to consider decaying the return type of f.)
I'd like to create a function that takes a weak pointer and any kind of functor (lambda, std::function, whatever) and returns a new functor that only executes the original functor when the pointer was not removed in the meantime (so let's assume there is a WeakPointer type with such semantics). This should all work for any functor without having to specify explicitly the functor signature through template parameters or a cast.
EDIT:
Some commenters have pointed out that std::function - which I used in my approach - might not be needed at all and neither might the lambda (though in my original question I also forgot to mention that I need to capture the weak pointer parameter), so any alternative solution that solves the general problem is of course is also highly appreciated, maybe I didn't think enough outside the box and was to focused on using a lambda + std::function. In any case, here goes what I tried so far:
template<typename... ArgumentTypes>
inline std::function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const std::function<void(ArgumentTypes...)>&& fun)
{
return [=] (ArgumentTypes... args)
{
if(pWeakPointer)
{
fun(args...);
}
};
}
This works well without having to explicitly specify the argument types if I pass an std::function, but fails if I pass a lambda expression. I guess this because the std::function constructor ambiguity as asked in this question. In any case, I tried the following helper to be able to capture any kind of function:
template<typename F, typename... ArgumentTypes>
inline function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const F&& fun)
{
return wrap(pWeakPointer, std::function<void(ArgumentTypes...)>(fun));
}
This now works for lambdas that don't have parameters but fails for other ones, since it always instantiates ArgumentTypes... with an empty set.
I can think of two solution to the problem, but didn't manage to implement either of them:
Make sure that the correct std::function (or another Functor helper type) is created for a lambda, i.e. that a lambda with signature R(T1) results in a std::function(R(T1)) so that the ArgumentTypes... will be correctly deduced
Do not put the ArgumentTypes... as a template parameter instead have some other way (boost?) to get the argument pack from the lambda/functor, so I could do something like this:
-
template<typename F>
inline auto wrap(WeakPointer pWeakPointer, const F&& fun) -> std::function<void(arg_pack_from_functor(fun))>
{
return wrap(pWeakPointer, std::function<void(arg_pack_from_functor(fun))(fun));
}
You don't have to use a lambda.
#include <iostream>
#include <type_traits>
template <typename F>
struct Wrapper {
F f;
template <typename... T>
auto operator()(T&&... args) -> typename std::result_of<F(T...)>::type {
std::cout << "calling f with " << sizeof...(args) << " arguments.\n";
return f(std::forward<T>(args)...);
}
};
template <typename F>
Wrapper<F> wrap(F&& f) {
return {std::forward<F>(f)};
}
int main() {
auto f = wrap([](int x, int y) { return x + y; });
std::cout << f(2, 3) << std::endl;
return 0;
}
Assuming the weak pointer takes the place of the first argument, here's how I would do it with a generic lambda (with move captures) and if C++ would allow me to return such a lambda:
template<typename Functor, typename Arg, typename... Args>
auto wrap(Functor&& functor, Arg&& arg)
{
return [functor = std::forward<Functor>(functor)
, arg = std::forward<Arg>(arg)]<typename... Rest>(Rest&&... rest)
{
if(auto e = arg.lock()) {
return functor(*e, std::forward<Rest>(rest)...);
} else {
// Let's handwave this for the time being
}
};
}
It is possible to translate this hypothetical code into actual C++11 code if we manually 'unroll' the generic lambda into a polymorphic functor:
template<typename F, typename Pointer>
struct wrap_type {
F f;
Pointer pointer;
template<typename... Rest>
auto operator()(Rest&&... rest)
-> decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )
{
if(auto p = lock()) {
return f(*p, std::forward<Rest>(rest)...);
} else {
// Handle
}
}
};
template<typename F, typename Pointer>
wrap_type<typename std::decay<F>::type, typename std::decay<Pointer>::type>
wrap(F&& f, Pointer&& pointer)
{ return { std::forward<F>(f), std::forward<Pointer>(pointer) }; }
There are two straightforward options for handling the case where the pointer has expired: either propagate an exception, or return an out-of-band value. In the latter case the return type would become e.g. optional<decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )> and // Handle would become return {};.
Example code to see everything in action.
[ Exercise for the ambitious: improve the code so that it's possible to use auto g = wrap(f, w, 4); auto r = g();. Then, if it's not already the case, improve it further so that auto g = wrap(f, w1, 4, w5); is also possible and 'does the right thing'. ]
GOAL:
I would like to achieve type-safe dynamic polymorphism (i.e. run-time dispatch of a function call) on unrelated types - i.e. on types which do not have a common base class. It seems to me that this is achievable, or at least theoretically sound. I will try to define my problem more formally.
PROBLEM DEFINITION:
Given the following:
two or more unrelated types A1, ..., An, each of which has a method called f, possibly with different signatures, but with the same return type R; and
a boost::variant<A1*, ..., An*> object v (or whatever other type of variant) which can and must assume at any time one value of any of those types;
My goal is to write instructions conceptually equivalent to v.f(arg_1, ..., arg_m); that would get dispatched at run-time to function Ai::f if the actual type of the value contained in v is Ai. If the call arguments are not compatible with the formal parameters of each function Ai, the compiler should raise an error.
Of course I do not need to stick to the syntax v.f(arg_1, ..., arg_m): for instance, something like call(v, f, ...) is also acceptable.
I tried to achieve this in C++, but so far I have failed to come up with a good solution (I do have a bunch of bad ones). Below I clarify what I mean by "good solution".
CONSTRAINTS:
A good solution is anything that lets me mimic the v.f(...) idiom, e.g. call_on_variant(v, f, ...);, and satisfies the following constraints:
does not require any sort of separate declaration for each function f that must be called this way (e.g. ENABLE_CALL_ON_VARIANT(f)) or for any list of unrelated types A1, ..., An that can be treated polymorphically (e.g. ENABLE_VARIANT_CALL(A1, ..., An)) somewhere else in the code, especially on global scope;
does not require to explicitly name the types of the input arguments when doing the call (e.g. call_on_variant<int, double, string>(v, f, ...)). Naming the return type is OK, so for instance call_on_variant<void>(v, f, ...) is acceptable.
Follows a demonstrative example that hopefully clarifies my wish and requirements.
EXAMPLE:
struct A1 { void f(int, double, string) { cout << "A"; } };
struct A2 { void f(int, double, string) { cout << "B"; } };
struct A3 { void f(int, double, string) { cout << "C"; } };
using V = boost::variant<A1, A2, A3>;
// Do not want anything like the following here:
// ENABLE_VARIANT_CALL(foo, <whatever>)
int main()
{
A a;
B b;
C c;
V v = &a;
call_on_variant(v, f, 42, 3.14, "hello");
// Do not want anything like the following here:
// call_on_variant<int, double, string>(v, f, 42, 3.14, "hello");
V v = &b;
call_on_variant(v, f, 42, 3.14, "hello");
V v = &c;
call_on_variant(v, f, 42, 3.14, "hello");
}
The output of this program should be: ABC.
BEST (FAILED) ATTEMPT:
The closest I got to the desired solution is this macro:
#define call_on_variant(R, v, f, ...) \
[&] () -> R { \
struct caller : public boost::static_visitor<void> \
{ \
template<typename T> \
R operator () (T* pObj) \
{ \
pObj->f(__VA_ARGS__); \
} \
}; \
caller c; \
return v.apply_visitor(c); \
}();
Which would work perfectly, if only template members were allowed in local classes (see this question). Does anybody have an idea how to fix this, or suggest an alternative approach?
Some time has passed, C++14 is being finalized, and compilers are adding support for new features, like generic lambdas.
Generic lambdas, together with the machinery shown below, allow achieving the desired (dynamic) polymorphism with unrelated classes:
#include <boost/variant.hpp>
template<typename R, typename F>
class delegating_visitor : public boost::static_visitor<R>
{
public:
delegating_visitor(F&& f) : _f(std::forward<F>(f)) { }
template<typename T>
R operator () (T x) { return _f(x); }
private:
F _f;
};
template<typename R, typename F>
auto make_visitor(F&& f)
{
using visitor_type = delegating_visitor<R, std::remove_reference_t<F>>;
return visitor_type(std::forward<F>(f));
}
template<typename R, typename V, typename F>
auto vcall(V&& vt, F&& f)
{
auto v = make_visitor<R>(std::forward<F>(f));
return vt.apply_visitor(v);
}
#define call_on_variant(val, fxn_expr) \
vcall<int>(val, [] (auto x) { return x-> fxn_expr; });
Let's put this into practice. Supposing to have the following two unrelated classes:
#include <iostream>
#include <string>
struct A
{
int foo(int i, double d, std::string s) const
{
std::cout << "A::foo(" << i << ", " << d << ", " << s << ")";
return 1;
}
};
struct B
{
int foo(int i, double d, std::string s) const
{
std::cout << "B::foo(" << i << ", " << d << ", " << s << ")";
return 2;
}
};
It is possible to invoke foo() polymorphically this way:
int main()
{
A a;
B b;
boost::variant<A*, B*> v = &a;
auto res1 = call_on_variant(v, foo(42, 3.14, "Hello"));
std::cout << std::endl<< res1 << std::endl;
v = &b;
auto res2 = call_on_variant(v, foo(1337, 6.28, "World"));
std::cout << std::endl<< res2 << std::endl;
}
And the output is, as expected:
A::foo(42, 3.14, Hello)
1
B::foo(1337, 6.28, World)
2
The program has been tested on VC12 with November 2013's CTP. Unfortunately, I do not know of any online compiler that supports generic lambdas, so I cannot post a live example.
OK, here's a wild shot:
template <typename R, typename ...Args>
struct visitor : boost::static_visitor<R>
{
template <typename T>
R operator()(T & x)
{
return tuple_unpack(x, t); // this needs a bit of code
}
visitor(Args const &... args) : t(args...) { }
private:
std::tuple<Args...> t;
};
template <typename R, typename Var, typename ...Args>
R call_on_variant(Var & var, Args const &... args)
{
return boost::apply_visitor(visitor<R, Args...>(args...), var);
}
Usage:
R result = call_on_variant<R>(my_var, 12, "Hello", true);
I've hidden a certain amount of work you need for calling a function by unpacking a tuple, but I believe this has been done elsewhere on SO.
Also, if you need to store references rather than copies of the arguments, this can possibly be done, but needs more care. (You can have a tuple of references. But you have to think about whether you also want to allow temporary objects.)
Unfortunately, this cannot be done in C++ (yet - see the conclusions). Follows a proof.
CONSIDERATION 1: [on the need of templates]
In order to determine the correct member function Ai::f to be invoked at run-time when the expression call_on_variant(v, f, ...) is met (or any equivalent form of it), it is necessary, given the variant object v, to retrieve the type Ai of the value being held by v. Doing so necessarily requires the definition of at least one (class or function) template.
The reason for this is that no matter how this is done, what is needed is to iterate over all the types the variant can hold (the type list is exposed as boost::variant<...>::types, check whether the variant is holding a value of that type (through boost::get<>), and (if so) retrieve that value as the pointer through which the member function invocation must be performed (internally, this is also what boost::apply_visitor<> does).
For each single type in the list, this can be done this way:
using types = boost::variant<A1*, ..., An*>::types;
mpl::at_c<types, I>::type* ppObj = (get<mpl::at_c<types, I>::type>(&var));
if (ppObj != NULL)
{
(*ppObj)->f(...);
}
Where I is a compile-time constant. Unfortunately, C++ does not allow for a static for idiom that would allow a sequence of such snippets to be generated by the compiler based on a compile-time for loop. Instead, template meta-programming techniques must be used, such as:
mpl::for_each<types>(F());
where F is a functor with a template call operator. Directly or indirectly, at least one class or function template needs to be defined, since the lack of static for forces the programmer to code the routine that must be repeated for each type generically.
CONSIDERATION 2: [on the need of locality]
One of the constraints for the desired solution (requirement 1 of the section "CONSTRAINTS" in the question's text) is that it shall not be necessary to add global declarations or any other declaration at any other scope than the one where the function call is being done. Therefore, no matter whether macro expansion or template meta-programming is involved, what needs to be done must be done in the place where the function call occurs.
This is problematic, because "CONSIDERATION 1" above has proved that it is needed to define at least one template to carry out the task. The problem is that C++ does not allow templates to be defined at local scope. This is true of class templates and function templates, and there is no way to overcome this restriction. Per §14/2:
"A template-declaration can appear only as a namespace scope or class scope declaration"
Thus, the generic routines we have to define in order to do the job must be defined elsewhere than at call site, and must be instantiated at call-site with proper arguments.
CONSIDERATION 3: [on function names]
Since the call_on_variant() macro (or any equivalent construct) must be able to handle any possible function f, the name of f must be passed in as an argument to our template-based, type resolving machinery. It is important to stress that only the name of the function shall be passed, because the particular function Ai::f that needs to be invoked must be determined by the template machinery.
However, names cannot be template arguments, because they do not belong to the type system.
CONCLUSION:
The combination of the three considerations above proves that this problem cannot be solved in C++ as of today. It requires either the possibility of using names as template arguments or the possibility of defining local templates. While the first thing is undesirable at least, the second one might make sense, but it is not being taken into consideration by the standardization committee. However, one exception is likely to be admitted.
FUTURE OPPORTUNITIES:
Generic lambdas, which are being strongly pushed to get into the next C++ standard, are in fact local classes with a template call operator.
Thus, even though the macro I posted at the end of the question's text will still not work, an alternative approach seems viable (with some tweaking required for handling return types):
// Helper template for type resolution
template<typename F, typename V>
struct extractor
{
extractor(F f, V& v) : _f(f), _v(v) { }
template<typename T>
void operator () (T pObj)
{
T* ppObj = get<T>(&_v));
if (ppObj != NULL)
{
_f(*ppObj);
return;
}
}
F _f;
V& _v;
};
// v is an object of type boost::variant<A1*, ..., An*>;
// f is the name of the function to be invoked;
// The remaining arguments are the call arguments.
#define call_on_variant(v, f, ...) \
using types = decltype(v)::types; \
auto lam = [&] (auto pObj) \
{ \
(*pObj)->f(__VA_ARGS__); \
}; \
extractor<decltype(lam), decltype(v)>(); \
mpl::for_each<types>(ex);
FINAL REMARKS:
This is an interesting case of type-safe call that is (sadly) not supported by C++. This paper by Mat Marcus, Jaakko Jarvi, and Sean Parent seems to show that dynamic polymorphism on unrelated types is crucial to achieve an important (in my opinion, fundamental and unavoidable) paradigm shift in programming.
I once solved this by simulating .NET delegates:
template<typename T>
class Delegate
{
//static_assert(false, "T must be a function type");
};
template<typename ReturnType>
class Delegate<ReturnType()>
{
private:
class HelperBase
{
public:
HelperBase()
{
}
virtual ~HelperBase()
{
}
virtual ReturnType operator()() const = 0;
virtual bool operator==(const HelperBase& hb) const = 0;
virtual HelperBase* Clone() const = 0;
};
template<typename Class>
class Helper : public HelperBase
{
private:
Class* m_pObject;
ReturnType(Class::*m_pMethod)();
public:
Helper(Class* pObject, ReturnType(Class::*pMethod)()) : m_pObject(pObject), m_pMethod(pMethod)
{
}
virtual ~Helper()
{
}
virtual ReturnType operator()() const
{
return (m_pObject->*m_pMethod)();
}
virtual bool operator==(const HelperBase& hb) const
{
const Helper& h = static_cast<const Helper&>(hb);
return m_pObject == h.m_pObject && m_pMethod == h.m_pMethod;
}
virtual HelperBase* Clone() const
{
return new Helper(*this);
}
};
HelperBase* m_pHelperBase;
public:
template<typename Class>
Delegate(Class* pObject, ReturnType(Class::*pMethod)())
{
m_pHelperBase = new Helper<Class>(pObject, pMethod);
}
Delegate(const Delegate& d)
{
m_pHelperBase = d.m_pHelperBase->Clone();
}
Delegate(Delegate&& d)
{
m_pHelperBase = d.m_pHelperBase;
d.m_pHelperBase = nullptr;
}
~Delegate()
{
delete m_pHelperBase;
}
Delegate& operator=(const Delegate& d)
{
if (this != &d)
{
delete m_pHelperBase;
m_pHelperBase = d.m_pHelperBase->Clone();
}
return *this;
}
Delegate& operator=(Delegate&& d)
{
if (this != &d)
{
delete m_pHelperBase;
m_pHelperBase = d.m_pHelperBase;
d.m_pHelperBase = nullptr;
}
return *this;
}
ReturnType operator()() const
{
(*m_pHelperBase)();
}
bool operator==(const Delegate& d) const
{
return *m_pHelperBase == *d.m_pHelperBase;
}
bool operator!=(const Delegate& d) const
{
return !(*this == d);
}
};
You can use it much like .NET delegates:
class A
{
public:
void M() { ... }
};
class B
{
public:
void M() { ... }
};
A a;
B b;
Delegate<void()> d = Delegate<void()>(&a, &A::M);
d(); // calls A::M
d = Delegate<void()>(&b, &B::M);
d(); // calls B::M
This works with methods that have no arguments. If you can use C++11, you can modify it to use variadic templates to handle any number of parameters. Without C++11, you need to add more Delegate specializations to handle specific numbers of parameters:
template<typename ReturnType, typename Arg1>
class Delegate<ReturnType(Arg1)>
{
...
};
template<typename ReturnType, typename Arg1, typename Arg2>
class Delegate<ReturnType(Arg1, Arg2)>
{
...
};
With this Delegate class you can also emulate .NET events, which are based on delegates.