How to pass the specific callback to a template function? - c++

I have the following code:
#include <iostream>
using namespace std;
template <class T>
int get_num(int k) {
return k + 3;
}
float get_num(float k) {
return k + 3;
}
template <class T1, class T2>
void function(T1 (*callback)(T2), T2 arg) {
callback(arg);
}
int main() {
// your code goes here
function(get_num, 3);
return 0;
}
I need to call the get_num() function with an int argument. But compiler gets this error:
prog.cpp: In function ‘int main()’: prog.cpp:21:21: error: no matching
function for call to ‘function(<unresolved overloaded function type>,
int)’ function(get_num, 3);
^ prog.cpp:15:6: note: candidate: template<class T1, class T2> void function(T1 (*)(T2), T2) void function(T1
(*callback)(T2), T2 arg) {
^~~~~~~~ prog.cpp:15:6: note: template argument deduction/substitution failed: prog.cpp:21:21: note: couldn't deduce
template parameter ‘T1’ function(get_num, 3);
How can it be done ?

After removing template <class T> from int get_num(int) to get a normal overload set, you can use Some programmer dude’s answer.
In this answer I want to elaborate how you can still use a function pointer based parameter.
If you switch the arguments to function at least gcc is able to deduce it:
template <typename T, typename U>
void function2(T arg, U(*callback)(T)) {
callback(arg);
}
clang doesn’t like it when you use U there, so if your return types will always be the same as your arguments, you can use T twice:
template <typename T>
void function2(T arg, T(*callback)(T)) {
callback(arg);
}
To resolve disambiguities like the one in your error message in general, you can also do the overload resolution manually with static_cast:
function(static_cast<float(*)(float)>(&get_num), 3.0f);
function(static_cast<int(*)(int)>(&get_num), 3);

One problem is that you have different types for return-type and argument-type for function, but in reality both are the same.
That means you could do something like
template<typename T, typename F = T(T)>
void function(F callback, T arg)
{
callback(arg);
}
The template argument F is just to simplify the callback argument declaration.

You have a template <class T> in front of your int get_num(int k). Lets assume for a moment it isnt there, then this works:
Sometimes you cannot change the function into a template, but need to work with function pointers to a function that has several overloads. The way to choose the right overload is to specify the type of the function pointer (because for different overloads the function pointers are of different type).
typedef int (* int_get_num_t)(int);
int main() {
int_get_num_t correct_overload = get_num;
function(correct_overload, 3);
return 0;
}
In case the int get_num(int k) is really supposed to be a template (then why the float one isnt?) then you simply have to pick the template version:
int_get_num_t correct_overload = get_num<int>;
where actually you could pass any type instead of int as your template get_num always takes an int and returns an int irrespective of the template parameter.
And finally... you actually dont need the second overload for get_num but you need only one template. And in that case you still need to pick the right template to get the function pointer:
template <typename T>
T get_num(T k) { return k + 3; }
template <class T1, class T2>
void function(T1 (*callback)(T2), T2 arg) {
callback(arg);
}
int main() {
int_get_num_t correct_overload = get_num<int>;
function(correct_overload, 3);
return 0;
}

Here's the one using the C++ functors.
#include <iostream>
using namespace std;
template<class T>
struct get_num : public std::unary_function<T,T>
{
T operator()(const T& k) {
return k+3;
}
};
template< class T1, class T2 >
void function( T1 fun, T2 arg)
{
fun(arg);
cout << fun(arg) << endl;
}
int main()
{
function(get_num<int>(), 3);
return 0;
}

The following code will work:
#include <iostream>
using namespace std;
template<typename T>
int get_num(int k) {
return k + 3;
}
float get_num(float k) {
return k + 3;
}
template<typename T1, typename T2> // Maybe here you want the `typename`, not the `class`
void f(T1 (*callback)(T2), T2 arg) {
callback(arg);
}
int main() {
// your code goes here
f(get_num<int>, 3); // The key point is here!
return 0;
}
The reason you get the compiling error is the compiler could not deduce the type T if you just use get_num, because all the arguments are nothing with the type T.

You have to specify the type of function
#include <iostream>
#include <string>
int get_num(int k) {
return k + 3;
}
float get_num(float k) {
return k + 3;
}
std::string get_num (double a)
{
return "this is a string " + std::to_string(a);
}
template <class T1, class T2>
using callback = T1(*)(T2);
template <class T1, class T2>
void function(callback<T1, T2> function, T2 arg) {
std:: cout << function(arg) << std::endl;
}
int main() {
// your code goes here
function<int, int>(get_num, 3);
function<std::string, double>(get_num, 3);
system("pause");
return 0;
}
Why 2 different template arguments? -The OP's question is not about optimization, it is about
How to pass the specific callback to a template function?
So, this is one of many implementations, solving the specific error.

I allowed myself to simplify a bit Your code. This should work fine:
#include <iostream>
using namespace std;
template <class T>
T get_num(T k) {
return k + 3;
}
template <class T1, class T2>
void function(T1 callback, T2 arg) {
callback(arg);
}
int main() {
function(get_num<int>, 3);
return 0;
}

I want to provide an solution which differs a bit.
I explain it inside the code to make it hopefully more comfortable to read and understand:
// create a helper class,
// which collects all callable classes to build one callable object later
template<class... Ts> struct funcs : Ts... { using Ts::operator()...; };
template<class... Ts> funcs(Ts...) -> funcs<Ts...>;
// instead of free functions, build objects with methods
// and use operator() instead of function names.
// this makes it easier to "understand" that this will be an callable object
struct Func1
{
int operator()(int k) {
return k + 3;
}
};
struct Func2
{
float operator()(float k) {
return k + 3;
}
};
// adapt your code to this:
template <class T1, class T2>
auto function(T1 callback, T2 arg) {
return callback(arg);
}
// and finaly you can use it this way, also with return types
// the central hack is:
// funcs{ Func1(), Func2() }
// this will generate a callable object with all the overloads
// from the inserted callable objects
int main() {
// your code goes here
std::cout << function(funcs{ Func1(), Func2() }, 3) << std::endl;
std::cout << function(funcs{ Func1(), Func2() }, (float)7.999) << std::endl;
return 0;
}

Related

Using template type as argument to std::invoke

Consider this code:
using namespace std;
struct FS
{
void print() { cout << "p\n"; }
int s;
};
template <typename T, typename F>
void myInvoke(T& t, F f)
{
invoke(f, t) = 10;
}
int main(int, char**)
{
FS fs;
myInvoke(fs, &FS::s);
cout << fs.s << "\n";
}
Is there anyway to avoid the runtime cost of passing the class member pointer to myInvoke?
I can of course do:
template <typename T>
void myInvoke(T& t)
{
invoke(&T::s, t) = 10;
}
// then call with
myInvoke(fs);
What I'd like to do:
template <typename T, typename P, P FS::* f>
void myInvoke(T& t)
{
invoke(f, t) = 30;
}
// call with:
myInvoke<FS, int ,&FS::s>(fs);
But without the typename P. Is there any way to make the call more concise so it can be called with:
myInvoke<FS, &FS::s>(fs);
I know this is a bit arcane, but it'd be really nice to be as concise as possible. Especially when you have widely used library functions.
EDIT:
Link to sandbox above code: https://godbolt.org/z/z4cGdPd3r
It seems you are looking for deduced Non-type template parameter (with auto) (C++17):
template <auto F, typename T>
void myInvoke(T& t)
{
invoke(F, t) = 10;
}
with usage:
myInvoke<&FS::s>(fs);
Demo

How can I get C++ to infer my template typename parameter?

I'd like to write a type alias template that resolves to the const of the template parameter for most types, like so:
template <typename T>
using TypeAlias = const T;
but for a particular type, say int, it simply resolves to T.
I've tried doing this with std::conditional, as well as specialization of structs containing the type alias, but in all cases, the compiler is unable to infer the type. My questions are: what am I doing wrong in the examples below? and How does one do this correctly?
Edit: I'm working in a very large codebase that handles a large number of types, and adds const to all of them in the definition of TypeAlias (which is actually a more complicated type, basically a container templated over const T). I'm trying to modify this codebase to accept a new type which cannot be const, while making minimal modifications. Explicitly specifying the type in all templated functions like foo isn't a workable solution. What I'm really looking for is a way to modify TypeAlias, and little to nothing else.
example 1:
#include <stdio.h>
#include <type_traits>
template <typename T>
using TypeAlias = typename std::conditional<std::is_same<int, T>::value,
T, typename std::add_const<T>::type>::type;
template <typename T>
void foo(TypeAlias<T> var) {
printf("var = %f\n", static_cast<double>(var));
}
int main(int argc, char *argv[]) {
const int a = 1;
const float b = 2;
const double c = 3;
foo(a);
foo(b);
foo(c);
return 0;
}
example 2:
template <typename T>
struct TypeHolder {
using type = const T;
};
template <>
struct TypeHolder<int> {
using type = int;
};
template <typename T>
void foo(typename TypeHolder<T>::type var) {
printf("var = %f\n", static_cast<double>(var));
}
int main(int argc, char *argv[]) {
int a = 1;
const float b = 2;
const double c = 3;
foo(a);
foo(b);
foo(c);
return 0;
}
Here's another way to remove const for a specific set of types, just add an overload and use SFINAE to constrain based on whether the deduced type is in the set or not:
#include <iostream>
#include <type_traits>
template <class T, class... Ts>
inline constexpr bool is_any_v = (... || std::is_same_v<T, Ts>);
template <class T>
inline constexpr bool int_or_short_v = is_any_v<T, int, short>;
template <class T>
std::enable_if_t<!int_or_short_v<T>> foo(const T) { std::cout << "const" << std::endl; }
template <class T>
std::enable_if_t<int_or_short_v<T>> foo(T) { std::cout << "non-const" << std::endl; }
int main() {
const int a = 1;
const short b = 2;
const float c = 3;
const double d = 4;
foo(a);
foo(b);
foo(c);
foo(d);
}
Try it on godbolt.org
In C++20, even easier:
#include <iostream>
#include <concepts>
template <class T, class... Ts>
concept any_of = (... || std::same_as<T, Ts>);
void foo(const auto) { std::cout << "const" << std::endl; }
void foo(any_of<int, short> auto) { std::cout << "non-const" << std::endl; }
int main() {
const int a = 1;
const short b = 2;
const float c = 3;
const double d = 4;
foo(a);
foo(b);
foo(c);
foo(d);
}
Try it on godbolt.org
As was mentioned in the comments, this is a non-deduced context so the template types will not be deduced. This is actually one of the tricks you can use to force the caller so explicitly set the template parameter.
What you could do is use if constexpr to differentiate between your two (or more) cases:
void foo_for_int(int x) { /* do something for ints */ }
template <typename T> foo_for_others(T const x) { /* do something for other types */ }
template <typename T>
void foo(T && t)
{
if constexpr (std::is_same_v<int, T>)
{
foo_for_int(t); // no need to forward an int
}
else
{
foo_for_others(std::forward<T>(t));
}
}

Error in passing function to function template

I have function templates :
template<typename T>
inline T fun3(T &x1, T &x2)
{
return std::pow(x1,2.0) + std::pow(x2,2.0);
}
template<typename T, typename U>
inline T fun5(U &a)
{
return (T(4.0+a*(-2.0),5.0+ a*3.0));
}
template<typename F, typename T>
void min(F fun1, T& v)
{
double x={10.0};
v=fun1(x);
}
int main()
{
double val;
min(fun3(fun5),val);
std::cout<<"value = "<<val<<"\n";
return 0;
}
I want to evaluate fun3(fun5(x)) and have functions as shown above. But getting error as no matching function for call to ‘Function5<double>::fun5(<unresolved overloaded function type>)’ obj1(o5.fun5(o3.fun3),-2.0,0.0,location,value);
Can someone explain how can I pass function to min()?
What will change if all these functions were class templates like:
template<typename T>
class Fun3 {
inline T fun3(T &x1, T &x2)
{
return std::pow(x1,2.0) + std::pow(x2,2.0);
}
};
template<typename T, typename U>
class Fun5 {
inline T fun5(U &a)
{
return (T(4.0+a*(-2.0),5.0+ a*3.0));
}
};
template<typename F, typename T>
class Min {
void min(F fun1, T& v)
{
double x={10.0};
v=fun1(x);
}
};
int main()
{
double val;
Fun5<double> o5;
Fun3<decltype (o5.fun5)> o3;
Min<???,decltype (o5.fun5)> obj; //What is here?
obj(o3.fun3(o5.fun5),val);
std::cout<<"value = "<<val<<"\n";
return 0;
}
I don't know what will go to commented line.
How can I use a function object (functor) here?
I want to evaluate fun3(fun5(x))
min([](auto x){ return fun3(fun5(x)); }, val);
There's no function composition in C++ standard library (though it can be defined with some effort.)
If you really want fun, at least try lambdas. They are simple.
I'd say stay away from templates in the way you want to use them. I am assuming you want a simple happy life to focus on productive thing and I may be wrong. Pardon.
Still, I worked on your code a bit and would say that don't confuse template and macros. It looks like the case at least to me.
Note that the template actually instantiate the code and for that all you can pass is arguments to whatever types and specify those types while template instantiating.
Here is a code sample at ideone - not exactly same but to show how something can be done.
For min(fun3(fun5),val);
If you really want fun3 behavior, pass it. Dont expect the result to be passed just like it works for macro.
.
#include <iostream>
#include <cmath>
using namespace std;
typedef double (*_typeofFun1)(double&);
typedef double (*_typeofFun3)(double&, double&);
template<typename T>
T fun3(T &x1, T &x2)
{
return std::pow(x1,2.0) + std::pow(x2,2.0);
}
template<typename T, typename U>
U fun5(T t, U &a)
{
//return (T(4.0+a*(-2.0),5.0+ a*3.0));
return t(a,a);
}
template <typename T>
T fun1Param(T& arg)
{
return 2*arg;
}
template<typename F, typename T>
void min(F fun1, T& v)
{
double x={10.0};
v=fun1(x);
}
int main()
{
double val = 1.0;
double d = fun5<_typeofFun3, double> (fun3, val);
fun3<double>(d, val);
min<_typeofFun1>(fun1Param,val);
std::cout<<"value = "<<val<<"\n";
return 0;
}

Referring to templated function in template

I would like to be able to name to a templated function in a template.
Since one can name a templated class using the "template template" syntax, and since one can name a function using the "function pointer" syntax, I was wondering whether there is a syntax (or a proposal) to name a function in a template without specifying to templates.
template<typename t_type>
struct A {
t_type value;
};
template<template<typename> class t_type>
struct B {
t_type<int> value;
};
template<int added>
constexpr int C (int value) {
return value + added;
}
template<int (*function)(int)>
constexpr int D (int value) {
return function(value);
}
// GOAL: Template argument referring to templated function
/*template<template<int> int (*function)(int)>
constexpr int E (int value) {
return function<1>(value);
}*/
int main() {
B<A> tt_good;
int fp_good = D< &C<1> >(0);
/*int fp_fail = E< &C >(0);*/
return 0;
}
One possible work-around for anyone interested in this functionality to first wrap the function D in a struct with a call method named (for example) "method", pass the struct into E as a "template template" parameter, and then call "method" in E.
The reason that I don't like this approach is that it requires a wrapper structure for every variadic function that might be used in this way.
Unfortunately, you cannot pass function templates as template parameters. The closest you can get is by using generic functors:
#include <iostream>
template <typename F>
void call(F f)
{
f("hello, world\n");
}
int main()
{
call([](auto value) { std::cout << value; });
}
If you don't have C++14 generic lambdas, you can write your own functors by hand:
#include <iostream>
template <typename F>
void call(F f)
{
f("hello, world\n");
}
struct print
{
template <typename T>
void operator()(T value) const
{
std::cout << value;
}
};
int main()
{
call(print());
}

Is it possible to use parameter pack to allow template function to accept equivalent types?

This question is related to one on SO a couple of years ago by Georg Fritzsche about transforming a parameter pack (Is it possible to transform the types in a parameter pack?). In the end, the individual types in the parameter pack can be transformed, e.g. by converting to corresponding pointer types.
I am wondering if it is possible to use this technique to write one standard function/functor and a set of wrapper functions (out of one template), so that the wrappers can take parameters of equivalent types and then call the standard function to do actual work.
Using the answer by Johannes Schaub - litb the original example below. Is it possible to write one template f, which can take any combinations of int/int*,char/char* and call a common function f_std(int*,char*) to do the work. (The number of parameters is not pre-specified.)
--- Update ---
For example, given int i; char c;, is it possible to write a caller using pack transformation such that the following works
call_ptr(f_std,i,c);
call_ptr(f_std,&i,c);
call_ptr(f_std,i,&c);
What I've tried so far is listed below (updated to clarify.). Basically, I tried to accept an list of not necessarily pointer types and convert them to pointer types, before making call to a std::function that takes pointer types. But the code does not compile. I don't know how to write a helper function to accept one function with a standard signature, but accept a parameter pack of something else.
Thanks in advance
#include <type_traits>
#include <functional>
using namespace std;
template<class... Args> struct X {};
template<class T> struct make_pointer { typedef T* type; };
template<class T> struct make_pointer<T*> { typedef T* type; };
template<template<typename...> class List,
template<typename> class Mod,
typename ...Args>
struct magic {
typedef List<typename Mod<Args>::type...> type;
};
/////////////////
// trying to convert parameter pack to pointers
template<class T> T* make_ptr(T x) { return &x; }
template<class T> T* make_ptr(T* x) { return x; }
template <typename Value, typename ...Args>
class ByPtrFunc
{
public:
typedef typename magic<X, make_pointer, Args...>::type PArgs;
Value operator()(Args... args) { return f(make_ptr(args)...); }
private:
std::function<Value (PArgs...)> _ptr_func;
}; //ByPtrFunc
//helper function to make call
template<typename A, typename ...Args>
static A call_ptr(std::function<A (Args...)> f, Args... args) {
return ByPtrFunc<A, Args...>{f}(args ...);
}
int main() {
typedef magic<X, make_pointer, int*, char>::type A;
typedef X<int*, char*> B;
static_assert(is_same<A, B>::value, ":(");
int i=0; char c='c';
function<int (int* pa,char* pb)> f_std = [](int* pa,char* pb)->int {return *pa + * pb;};
f_std(&i,&c);
//////////////////
//Is the following possible.
call_ptr(f_std,i,c);
call_ptr(f_std,&i,c);
call_ptr(f_std,i,&c);
return 0;
}
This answers your question syntax-wise, if I've understood it correctly: yes, it's possible.
// given int or char lvalue, returns its address
template<class T>
T* transform(T& t) {
return &t;
}
// given int* or char*, simply returns the value itself
template<class T>
T* transform(T* t) {
return t;
}
// prints out the address corresponding to each of its arguments
void f_std() {
}
template<class Arg, class... Args>
void f_std(Arg arg, Args... args) {
std::cout << (void*)arg << std::endl;
f_std(args...);
}
// converts int to int*, char to char*, then calls f_std
template<class... Args>
void f(Args... args) {
f_std(transform(args)...);
}
Unfortunately, calling f will pass int and char arguments by value, and hence copy them. To fix this, use perfect forwarding in the definition of f:
template<class... Args>
void f(Args&&... args) {
f_std(transform(std::forward<Args>(args))...);
}
Driver:
int main() {
int x = 1;
char c = 'a';
cout << (void*)&x << endl;
cout << (void*)&c << endl;
f(x, &x, c, &c);
}
Output (example; ran it on my machine just now):
0x7fff36fb5ebc
0x7fff36fb5ebb
0x7fff36fb5ebc
0x7fff36fb5ebc
0x7fff36fb5ebb
0x7fff36fb5ebb
Following may help:
template <typename T> T* make_pointer(T& t) { return &t; }
template <typename T> T* make_pointer(T* t) { return t; }
template <typename Ret, typename... Args, typename ...Ts>
Ret call_ptr(std::function<Ret (Args*...)> f, Ts&&...args)
{
static_assert(sizeof...(Args) == sizeof...(Ts), "Bad parameters");
f(make_pointer(std::forward<Ts>(args))...);
}
Now, use it:
void f_std(int*, char*) { /* Your code */ }
int main(int argc, char *argv[])
{
int i;
char c;
std::function<void (int*, char*)> f1 = f_std;
call_ptr(f1, i, c);
call_ptr(f1, i, &c);
call_ptr(f1, &i, c);
call_ptr(f1, &i, &c);
return 0;
}
For reference, below is what worked for me, based on the accepted answer #Jarod42 and the type transformation "magic". slightly more general and with added type checking. Turns out type-transformation is simply a pattern expansion.
#include <type_traits>
#include <functional>
#include <iostream>
using namespace std;
/////////////////
// convert parameter pack to pointers
//types
template<class T> struct make_ptr_t { typedef T* type; };
template<class T> struct make_ptr_t<T*> { typedef T* type; };
//values
template<class T> T* make_ptr(T& x) { return &x; }
template<class T> T* make_ptr(T* x) { return x; }
/////////////////////////////////////
// (optional) only for type checking
template<class... Args> struct X {};
template<template<typename...> class List,
template<typename> class Mod,
typename ...Args>
struct magic {
typedef List<typename Mod<Args>::type...> type;
};
//helper function to make call
template<typename A, typename ...PArgs, typename ...Args>
static A call_ptr(std::function<A (PArgs...)> f, Args... args) {
static_assert(is_same<X<PArgs...>,typename magic<X, make_ptr_t, Args...>::type>::value, "Bad parameters for f in call_ptr()"); //type checking
return f(make_ptr(args)...);
}
int main() {
int i=0; char c='c'; string s="c";
function<int (int* pa,char* pb)> f_std = [](int* pa,char* pb)->int {return *pa + * pb;};
f_std(&i,&c);
cout << call_ptr(f_std,i,c) << endl;
cout << call_ptr(f_std,&i,c) << endl;
cout << call_ptr(f_std,i,&c) << endl;
//cout << call_ptr(f_std,i,s) << endl; //complains about bad parameters.
return 0;
}