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

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();
}

Related

What is the usecase of calling hana::is_valid with a nullary function?

Boost.Hana offers boost::hana::is_valid to check whether a SFINAE-friendly expression is valid.
You can use it like this
struct Person { std::string name; };
auto has_name = hana::is_valid([](auto&& p) -> decltype((void)p.name) { });
Person joe{"Joe"};
static_assert(has_name(joe), "");
static_assert(!has_name(1), "");
However, there's a note about the argument to is_valid being a nullary function:
To check whether calling a nullary function f is valid, one should use the is_valid(f)() syntax. […]
How can I even use it by passing to it a nullary function? I mean, if a function is nullary, then how is its body gonna have any dependent context to which SFINAE can apply?
I think that maybe "lambda captures" might have something to do with the answer, but I can't really figure it out how.
Use case is that of checking that f is actually nullary, e.g
if constexpr (is_valid(f)()) {
f(); // Treat f as a "no args function"
} else if constexpr (is_valid(f, arg1)) {
f(arg1);
}
what the documentation says is that unlike functions of non zero arity, the is_valid predicate can only be invoked in the form:
is_valid(f)(); // Invoking "is_valid(f)", i.e. no parentheses, does NOT
// check that f is a nullary function.
reminder: to check whether e.g. a 2 arguments function call is valid you can say:
is_valid(f, arg1, arg2);
// or
is_valid(f)(arg1, arg2)
Take for example the following Demo
void f0()
{
std::cout << "Ok f0\n";
}
void f1(int)
{
std::cout << "Ok f1\n";
}
template <class F>
void test(F fun)
{
if constexpr (hana::is_valid(fun)())
{
fun();
}
else if constexpr (hana::is_valid(fun, 2))
{
fun(2);
}
}
int main() {
test(f0);
test(f1);
}
It may be obvious, but you have to keep in mind that SFINAE does not happen ON f0 or f1. SFINAE happens in the guts of is_valid between the different flavors of is_valid_impl (comments mine):
// 1
template <
typename F, typename ...Args, typename = decltype(
std::declval<F&&>()(std::declval<Args&&>()...)
)>constexpr auto is_valid_impl(int) { return hana::true_c; }
// 2
template <typename F, typename ...Args>
constexpr auto is_valid_impl(...) { return hana::false_c; }
// Substitution error on 1 will trigger version 2
So your question
"I mean, if a function is nullary, then how is its body gonna have any dependent context to which SFINAE can apply?"
has little meaning since SFINAE does not happen on the user provided function. After all, we are setting up nothing to enable SFINAE on our functions. Implementing SFINAE requires to provide more than 1 candidates that "guide" the instantiation process (check SFINAE sono buoni).
The term "SFINAE friendly" here, has to do with f (our function) being usable as type parameter for the SFINAE implementation in is_valid. For example, if in our Demo f was overloaded (replace f1(int) with f0(int)) you would get a substitution error:
<source>:22:6: note: candidate: 'template<class F> void test(F)'
22 | void test(F fun)
| ^~~~
<source>:22:6: note: template argument deduction/substitution failed:
because when the compiler reaches the deepest point of is_valid_impl it tries to instantiate the favorable version (version 1, that doesn't have ... parameter) but it cannot tell what the type of F is and produces a hard error.
For reference, the way SFINAE works is that if it could use type F, the compiler would:
make an attempt on version 1
If successfull return true (so IT IS valid)
If not successfull it would go for version 2 (substitution error is not a failure) which does not use type F as F(Args...) and hence produce a false.

template function pointers and lambdas

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.

Why does template argument deduction failed with variadic template parameters of a std::function callback?

Let's consider the following functions:
// run_cb_1(): Explicitly defined prototype
void run_cb_1(const std::function<void(int)> & callback, int p)
{
callback(p);
}
// run_cb_2(): One template parameter
template <typename T>
void run_cb_2(const std::function<void(T)> & callback, const T & t)
{
callback(t);
}
// run_cb_3(): Variable number of template parameters
template <typename ... Args>
void run_cb_3(const std::function<void(Args...)> & callback, const Args & ... args)
{
callback(args...);
}
Now if I want to use these functions as follows:
int main()
{
auto f = [](int a){
std::cout << a << '\n';
};
run_cb_1(f, 5); // OK
run_cb_2(f, 5); // KO --> I understand why
run_cb_2<int>(f, 5); // OK
run_cb_3(f, 5); // KO --> I understand why
run_cb_3<int>(f, 5); // KO --> I don't understand why...
return 0;
}
I get a "no matching function call" with run_cb_2() and run_cb_3() while it works perfectly fine with run_cb_1().
I think it behaves as expected because I did not provided the type for the template argument (since it can not be deduced trivially as it is for run_cb_1()).
But specifying the template type solves the problem for run_cb_2() (as I would expect) but not for run_cb_3().
I know I can solve it either by explicitly declaring f as:
std::function<void(int)> f = [](int a){
std::cout << a << '\n';
};
or by passing f as:
run_cb_2(std::function<void(int)>(f), 5);
run_cb_3(std::function<void(int)>(f), 5);
My question is: Why does the template argument deduction fail with run_cb_3() (with variadic template parameters) even when explicitly specifying the template type(s) ?
It is obvious that I missed something (maybe basic) but I don't know what it is.
Any help will be appreciated.
The reason this fails is because there isn't just one type the compiler can use. When you do
run_cb_2<int>(f, 5);
The compiler looks at run_cb_2 and sees that there is only one template parameter. Since you've provided that it skips the deduction phase and stamps out run_cb_2<int>.
With
run_cb_3<int>(f, 5);
You're in a different boat. run_cb_3 has a variadic template parameter which means just supplying int is not enough to skip the deduction. You specified the first argument, but there could be more so it goes into the argument deduction phase to figure it out. That means it checks callback to make sure what it deduces there matches what it deduces for args. Since the lambda is not a std::function it can't deduce Args... from it. Once that happens the compiler stops and issues an error.
With run_cb_3<int>, you don't explicitly provide full Args..., just the first type; it might have other.
It is used for example in function such as std::make_unique:
template <class T, class... Args>
std::unique_ptr<T> make_unique(Args&&... args);
and
std::make_unique<MyObj>(var1, var2); // T = MyObj
// Args... = [decltype((var1)), decltype((var2))]
Extra args are deduced from argument.
To force evaluation, you might use:
(&run_cb_3<int>)(f, 5); // OK
Demo

How do I use perfect forwarding when writing template functions that wrap existing functions and check for errors?

I'm wanting to wrap a number of function calls to an existing C library, which calls the function, checks if an error condition has been set, and then returns the value of the function, if any. (Specifically, this is for OpenGl, but would work for legacy C functions as well.) This is complicated by the fact that the functions may return void, which needs to be handled separately; and by the fact that I want to throw exceptions, which stops me from doing the check in the destructor of a guard object when it goes out of scope.
The following code basically works:
void check_for_error() {
// check and handle legacy error messages
// if (errno != 0)
// if (glGetError() != GL_NO_ERROR)
// throw std::runtime_error{"suitable error message"};
}
template <class R, class... Args>
using RvalFunc = R(*)(Args...);
// specialisation for funcs which return a value
template <class R, class... Args>
R exec_and_check(RvalFunc<R, Args...> func, Args... args) {
R rval = func(std::forward<Args>(args)...);
check_for_error();
return rval;
}
template <class... Args>
using VoidFunc = void(*)(Args...);
// specialisation for funcs which return void - don't store rval
template <class... Args>
void exec_and_check(VoidFunc<Args...> func, Args... args) {
func(std::forward<Args>(args)...);
check_for_error();
}
example usage:
exec_and_check(glBindBuffer, target, name);
FILE *pf = exec_and_check(fopen, "filename.txt", "rb");
...as opposed to...
glBindBuffer(target,name);
check_for_error();
FILE *pf = fopen("filename.txt", "rb");
check_for_error();
...where the checks might get missed, and which clutter up the code. I'd prefer the R exec_and_check(RvalFunc<R, Args...> func, Args... args) to include a universal reference for forwarding (ie. Args&&... args), but that substitution causes a compilation error - Clang gives note: candidate template ignored: deduced conflicting types for parameter 'Args' (<int, int> vs. <const int &, const int &>), as an example.
How would I modify this code to accept universal references? Or have I missed something, and there's a much better way to error check legacy code?
The problem is that you have two template functions, which, as far as the compiler is concerned, differ only by return type. To resolve this, you can use SFINAE as follows:
// specialisation for funcs which return a value
template <class R, class... Args>
std::enable_if_t<!std::is_void<R>::value, R>
exec_and_check(RvalFunc<R, Args...> func, Args... args) {
R rval = func(std::forward<Args>(args)...);
check_for_error();
return rval;
}
and that fixes the problem (by preventing the above template function from matching when R is void).
Live demo

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