template function pointers and lambdas - c++

Hi I'm trying to sort out an issue with the following code:
template<typename... Args>
using Func = void (*)(Args... args);
template<typename... Args>
void do_test(Func<Args&...> f, Args&... args) {
for (int i = 0; i != 100; i++)
f(args...);
}
int main(){
int x = 0;
do_test(Func<int&>([](int &y) { y++; }), x); // OK
// Error - mismatched types 'void (*)(Args& ...)' and 'main()::<lambda(int&)>'
do_test([](int &y) { y++; }, x);
return x;
}
https://godbolt.org/z/UaXxFJ
Can anyone explain why it is necessary to wrap the lambda in Func<int&>( )? Is there a way to avoid it? - because if the argument list is non-trivial it becomes quite tedious having to list out the argument types twice.
The goal here is to make a visitor pattern that the compiler can optimize away. I'm using it for an image processing algorithm where I want to reuse the code of the outer loops, with various bits of inner code. The Args are being used as something similar to a lambda capture, except using traditional function pointers so that the compiler can optimize them away - which it seems not to be able to do with std::function<>

You can just allow the function to take any type, whether function pointer or lambda:
template<typename F, typename... Args>
void do_test(F f, Args&... args) {
for (int i = 0; i != 100; i++)
f(args...);
}
Depending on your use case, consider taking f by-const-reference or forwarding reference (i.e. F&&), as well.
You should also consider changing the way you take the args function parameters. Usually in such a situation you would take them by forwarding reference, meaning Args&&... args instead of Args&... args. Otherwise you won't be able to call the function with rvalues arguments.
Or if you have some specific reason to accept only this one specific function pointer type, you can make the first function parameter a non-deduced context, given that the template arguments can already be deduced from the other function parameters:
template<typename... Args>
void do_test(std::type_identity_t<Func<Args&...>> f, Args&... args) {
for (int i = 0; i != 100; i++)
f(args...);
}
std::type_identity_t is a C++20 feature, but can be easily implemented:
template<typename T>
struct type_identity {
using type = T;
};
template<typename T>
using type_identity_t = typename type_identity<T>::type;
Everything left to the scope resolution operator :: in type_identity<T>::type is a non-deduced context and so the first function parameter will not be used to deduce the Args, which in turn means that implicit conversions will be considered (e.g. the lambda to function pointer conversion).
Alternatively, as mentioned by #FrançoisAndrieux in the question comments, you can use the lambda + trick to convert the lambda to a function pointer at the call site:
do_test(+[](int &y) { y++; }, x);
Also note that taking a function pointer of this specific type means that the function can only be called with functions that have exactly this type. For example args is always deduced to a reference type, so any possible function than may be used with this one must take only reference parameters. This is usually not what you want. Usually you want the loose behavior of std::function<R(Args...)>, which can be constructed from any function object that is callable with the specified Args and returns something that can be implicitly converted to R.

Related

C++11 function signature with variadic std::function

I'm trying to implement a function that takes an std::function which returns an it and might get any number of parameters.
I've tried the following but it doesn't compile and I can't understand what the error means.
template <typename ...Args>
void ThrowOnError(std::function<int(Args...)> func, Args... args)
{
int err = func(args...);
if (err < 0)
throw std::exception();
}
int f()
{
return 42;
}
int f(int x)
{
return x;
}
int main()
{
ThrowOnError(f);
ThrowOnError(f, 1);
}
I tried moving the templated function to header but it didn't work, also if I comment out the f(int x) function and only leave the call with only f , I still get a no matching overloaded function found and 'void ThrowOnError(std::function<int(Args...)>,Args...)': could not deduce template argument for 'std::function<int(Args...)>' from 'int (int)'
What is the problem here? what am I missing in the function?
P.S - I would like an answer which takes an std::function if possible, and not add another typename for the functor type.
You are not providing a std::function as a parameter and deduction can't take place.
In other there, to assign the function to the std::function, you must know the actual type. To find it, deduction must happen. For deduction to happen you should first assign the function pointer to the std::function, but the type of the latter is unknown (because deduction didn't take place yet).
So on in a loop.
Moreover, when you do this:
ThrowOnError(f);
It's impossible for the compiler to know what f you want to use.
You should rather do something like this:
ThrowOnError(std::function<int()>{static_cast<int(*)()>(f)});
Or this (if you accept to use another template parameter for the functor):
ThrowOnError(static_cast<int(*)()>(f));
This way you are picking the right function up from the overload set explicitly and the compiler has not to guess your intentions.
As mentioned, the latter would work fine if you accept to modify also the ThrowOnError function as it follows:
template <typename F, typename ...Args>
void ThrowOnError(F func, Args... args)
{
int err = func(args...);
if (err < 0)
throw std::exception();
}
Or even better:
template <typename F, typename ...Args>
void ThrowOnError(F &&func, Args&&... args)
{
int err = std::forward<F>(func)(std::forward<Args>(args)...);
if (err < 0)
throw std::exception();
}

How to make a SFINAE-based Y combinator in C++?

I was thinking about the implicit templates of C++14, and I'm trying to declare a function to match an specific argument type (SFINAE and traits still give me headaches). I'm not sure how to explain what I want, but I'm trying to make a Y combinator (just to see if it's possible, not intended for production).
I'm trying to declare a function:
template<typename T>
my_traits<T>::return_type Y(T t) {
// ...
};
Such that T is a function (or a functor) that matches
std::function<R(F, Args...)>
// where F (and above return_type) will be
std::function<R(Args...)>
Which would take any number of arguments, but the first should be a function with the same return type and the same arguments (except this function itself). The first parameter to the operator () of the functor is a template.
The usage I want to achieve:
auto fib = [](auto myself, int x) {
if(x < 2)
return 1;
return myself(x - 1) + myself(x - 2);
};
// The returned type of fib should be assignable to std::function<int(int)>
I wasn't able to take the return type of the T type (because of the overloaded operator ()). What I'm trying to make is possible? How could I make it?
Edit:
Seeing it from a different angle, I'm trying to make this work:
struct my_functor {
template<typename T>
char operator () (T t, int x, float y) { /* ... */ };
};
template<typename T>
struct my_traits {
typedef /* ... */ result_type;
/* ... */
};
// I want this to be std::function<char(int, float)>, based on my_functor
using my_result =
my_traits<my_functor>::result_type;
It is not possible in C++14 return type deduction to deduce int(int) out of int(T, int) as OP desires.
However, we can mask the first parameter of the result using the following approach. The struct YCombinator is instantiated with a non-recursive function object member, whose first argument is a version of itself without the first argument. YCombinator provides a call operator that receives the arguments of the non-recursive function and then returns its function object member after substituting itself for the first argument. This technique allows the programmer to avoid the messiness of myself(myself, ...) calls within the definition of the recursive function.
template<typename Functor>
struct YCombinator
{
Functor functor;
template<typename... Args>
decltype(auto) operator()(Args&&... args)
{
return functor(*this, std::forward<Args>(args)...);
}
};
A make_YCombinator utility template allows for a streamlined usage pattern. This compiles run runs in GCC 4.9.0.
template<typename Functor>
decltype(auto) make_YCombinator(Functor f) { return YCombinator<Functor> { f }; }
int main()
{
auto fib = make_YCombinator([](auto self, int n) -> int { return n < 2 ? 1 : self(n - 1) + self(n - 2); });
for (int i = 0; i < 10 ; ++i)
cout << "fib(" << i << ") = " << fib(i) << endl;
return 0;
}
Since the non-recursive function is not defined at time that the recursive function is defined, in general the recursive function must have an explicit return type.
Edit:
However, it may be possible for the compiler to deduce the return type in certain cases if the programmer takes care to indicate the return type of the recursive function before use of the non-recursive function. While the above construction requires an explicit return type, in the following GCC 4.9.0 has no problem deducing the return type:
auto fib = make_YCombinator([](auto self, int n) { if (n < 2) return 1; return self(n - 1) + self(n - 2); });
To pin this down just a bit further, here is a quote from the draft C++14 standard on return type deduction [7.1.6.4.11]:
If the type of an entity with an undeduced placeholder type is needed
to determine the type of an expression, the program is ill-formed.
Once a return statement has been seen in a function, however, the
return type deduced from that statement can be used in the rest of the
function, including in other return statements. [ Example:
auto n = n; // error, n’s type is unknown
auto f();
void g() { &f; } // error, f’s return type is unknown
auto sum(int i) {
if (i == 1)
return i; // sum’s return type is int
else
return sum(i-1)+i; // OK, sum’s return type has been deduced
}
—end example ]
It's a really hacky approach, and has severe limitations, but here it goes:
First, we need a class that pretends to support every possible operation (as far as possible), such as the fake_anything class. Note that this isn't perfect since at a minimum . and :: won't work. To fake a functor, we give it a function call operator:
template<class... Ts> fake_anything operator()(Ts&&...) const;
Knowing that the lambda has only one operator(), and that operator() has only one template parameter allows us to extract its signature with decltype(&T::operator()<fake_anything>).
For this to work, the lambda's return type must be explicitly specified; it can't use deduction, since otherwise the deduced return types will probably conflict.
Finally we can obtain the other arguments to the lambda and the return type using the standard partial specialization approach:
template<class T>
struct extract_signature;
template<class T, class R, class FA, class...Args>
struct extract_signature<R (T::*)(FA, Args...)> {
static_assert(std::is_same<fake_anything, std::decay_t<FA>>::value, "Unexpected signature");
using type = std::function<R(Args...)>;
};
template<class T, class R, class FA, class...Args>
struct extract_signature<R (T::*)(FA, Args...) const> {
static_assert(std::is_same<fake_anything, std::decay_t<FA>>::value, "Unexpected signature");
using type = std::function<R(Args...)>;
};
// other cv- and ref-qualifier versions omitted - not relevant to lambdas
// we can also static_assert that none of Args is fake_anything, or reference to it, etc.
And add an alias template to hide all the ugliness of the hack:
template<class T>
using signature_t = typename extract_signature<decltype(&T::template operator()<fake_anything>)>::type;
And finally we can check that
static_assert(std::is_same<signature_t<decltype(fib)>,
std::function<int(int)>>::value, "Oops");
Demo.
The limitations:
The return type of operator() must be explicitly specified. You cannot use automatic return type deduction, unless all of the return statements return the same type regardless of the return type of the functor.
The faking is very imperfect.
This works for operator() of a particular form only: template<class T> R operator()(T, argument-types...) with or without const, where the first parameter is T or a reference to possibly cv-qualified T.

Continue with the continuation monad tuple. Whats wrong?

Following with the tuple continuation monad, say I define a functor std_tuple to go from the cathegory of the monad-tuple to std::tuple:
auto std_tuple = [](auto... args)
{
return [=](auto f){ return f(std::make_tuple(args...)); };
};
Now we can use monad-tuples in contexts expecting std::tuple:
template<typename... ARGS>
void f( const std::tuple<ARGS...>& t ){}
int main()
{
tuple(1,2,3)(std_tuple)(f);
}
So far so good. Except this doesn't compile. Clang 3.4.1 complains:
note: candidate template ignored: couldn't infer template argument '$auto-1-0'
on the f(t) call inside the std_tuple functor.
Is this correct, are not those template argumments deducible? In case afirmative, why?
A simple case that reproduces your problem:
void f(int) {}
void f(double) {}
template<class T> void call_with_3( T t ) { t(3); }
int main() {
call_with_3( f );
}
Here we can see that which f to call cannot be determined at the point where we pass it to call_with_3. Now, you seemingly don't have multiple overloads (you only have one f!), but...
A template is not an instance. A template function is a factory of functions, not a function.
There is no object or value there to pass around.
When you pass a function name as an argument, overload resolution kicks in. If the target type is known (as a function reference or pointer) it is used to do overload resolution on the function name.
In this case, you are passing a function name to a template (auto argument), so there is no overload resolution that can be done, so no particular value can be found, so you get an error.
You can create an object whose effect is to do overload resolution on the invoked arguments with a given function name. I call them overload set objects.
static struct f_overload_set_t {
template<class... Args>
auto operator()(Args&&... args) const {
return f(std::forward<Args>(args)...);
}
} f_overload_set;
in C++11 you need a ->decltype( f( std::declval<Args>()... ) ) after the const.
Now f_overload_set(blah) will, when invoked will (almost) do what happens when you f(blah), but f_overload_set is an actual object. So you can pass it around.
Macros that generate such overload sets are relatively easy to write. They can also use lambdas, as the above is a lot like a stateless lambda if you think about it.
The nice thing about the stateless lambda based macro overload set generator is that it can be created at point-of-use. From #dyp's comment above:
#define OVERLOAD_SET( FUNC )\
([](auto&&... args){\
return FUNC(std::forward<decltype(args)>(args)...);\
})
(note: no brackets around FUNC, as that blocks ADL). Brackets around everything else, because otherwise if used within a subscript operation (operator[]), it would be parsed as a [[ starting an attribute, among other spots (thanks to #ecatmur))
which makes your code:
template<typename... ARGS>
void f( const std::tuple<ARGS...>& t ){}
int main() {
tuple(1,2,3)(std_tuple)(OVERLOAD_SET(f));
}

Polymorphic signature of function as template argument (using lambdas)

I'm trying hard for some hours and didn't manage to get this working.
I have a templated class spinlock:
template<typename T> class spinlock {
// ...
volatile T *shared_memory;
};
I'm trying to create something like this:
// inside spinlock class
template<typename F, typename... Ars>
std::result_of(F(Args...))
exec(F fun, Args&&... args) {
// locks the memory and then executes fun(args...)
};
But I'm trying to use a polymorphic function so that I can do this:
spinlock<int> spin;
int a = spin.exec([]() {
return 10;
});
int b = spin.exec([](int x) {
return x;
}, 10); // argument here, passed as x
// If the signature matches the given arguments to exec() plus
// the shared variable, call it
int c = spin.exec([](volatile int &shared) {
return shared;
}); // no extra arguments, shared becomes the
// variable inside the spinlock class, I need to make
// a function call that matches this as well
// Same thing, matching the signature
int d = spin.exec([](volatile int &shared, int x) {
return shared + x;
}, 10); // extra argument, passed as x... should match too
// Here, there would be an error
int d = spin.exec([](volatile int &shared, int x) {
return shared + x;
}); // since no extra argument was given
Basically, I'm trying to make an exec function that accepts F(Args...) or F(volatile T &, Args...) as an argument.
But I can't manage to make automatic detection of types.
How could I accomplish that?
Firstly, this signature will not compile:
// inside spinlock class
template<typename F, typename... Ars>
std::result_of(F(Args...))
exec(F fun, Args&&... args) {
// locks the memory and then executes fun(args...)
};
The return type needs to be
typename std::result_of<F(Args...)>::type
If your compiler implements N3436 then this function will not participate in overload resolution when fun(args...) is not a valid expression, but that is not required in C++11 and not implemented by many compilers yet. You will need to implement your own SFINAE check to prevent result_of giving an error when fun(args...) is not valid, or rewrite it without result_of
template<typename F, typename... Args>
auto
exec(F fun, Args&&... args) -> decltype(fun(std::forward<Args>(args)...))
{
// locks the memory and then executes fun(args...)
}
Then you can overload it for functions that need the additional parameter passed in:
template<typename F, typename... Args>
auto
exec(F fun, Args&&... args) -> decltype(fun(*this->shared_memory, std::forward<Args>(args)...))
{
// locks the memory and then executes fun(*shared_memory, args...)
}
When fun(std::forward<Args>(args)...) is not valid the first overload will not participate in overload resolution. When fun(*this->shared_memory, std::forward<Args>(args)...) is not valid the second overload will not participate in overload resolution. If neither is valid the call will be ill-formed, if both are valid the call will be ambiguous.

looping over all arguments of a function in C++

I want to do identical processing to a bunch of arguments of a function. Is there a way to loop over all arguments ? I am doing it the way represented in following code, but want to see if there is a compact way to do this.,
void methodA(int a1, int a2, int b1, double b2){
//.. some code
methodB(a1, f(a1));
methodB(a2, f(a2));
methodB(b1, f(b1));
methodB(b2, f(b2));
// more code follows ...
}
int f(int a){
// some function.
return a*10;
}
double f(double b){
return b/2.0;
}
You could use variadic templates:
template <typename T, typename ...Args>
void methodAHelper(T && t, Args &&... args)
{
methodB(t, f(t));
methodAHelper(std::forward<Args>(args)...);
}
void methodAHelper() { }
template <typename ...Args>
void methodA(Args &&... args)
{
// some code
methodAHelper(std::forward<Args>(args)...);
// some other code
}
You can possibly get rid of the && and the forwarding if you know that your methodB call doesn't know about rvalue references, that would make the code a bit simpler (you'd have const Args &... instead), for example:
methodAHelper(const T & t, const Args &... args)
{
methodB(t, f(t));
methodAHelper(args...);
}
You might also consider changing methodB: Since the second argument is a function of the first argument, you might be able to only pass the first argument and perform the call to f() inside the methodB(). That reduces coupling and interdependence; for example, the entire declaration of f would only need to be known to the implementation of methodB. But that's depends on your actual situation.
Alternatively, if there is only one overload of methodB whose first argument is of type T, then you could just pass a std::vector<T> to methodA and iterate over it:
void methodA(const std::vector<T> & v)
{
// some code
for (auto it = v.cbegin(), end = v.cend(); it != end; ++it)
methodB(*it, f(*it));
// some more code
}
int main() { methodA(std::vector<int>{1,2,3,4}); }
Yes there is, the concept you're looking for is called a variadic function.
Depending on what you are trying to do. The simplest thing might to revisit your function and see if it can take an array or std::vector as an argument. Might be much simpler that going the variadic route