call template function with async - c++

need to run a function asynchronously, when function takes template argument. Code below does not compile, any help?
template<typename T>
void say(int n, T t) {
cout << " say: " << n << " " << t << endl;
}
template<typename F, typename... Ts>
inline auto reallyAsync(F&& f, Ts&&... params){
return std::async(
std::launch::async,
std::forward<F>(f),
std::forward<Ts>(params)...);
}
int main() {
int n = 10; float x = 100;
say(n, x); // works
reallyAsync(&say, n, x) ; // does not work
}

say is a function-template, you cannot take the address of a function-template because its not yet a function (see comments):
int main() {
int n = 10; float x = 100;
say(n, x); // works because of template argument deduction
reallyAsync(&say, n, x); //fails because say isn't a resolved function.
}
you can however, pass an instantiation of say:
int main() {
int n = 10; float x = 100;
say(n, x); // works
reallyAsync(&say<decltype(x)>, n, x);
}
Outputs:
say: 10 100
say: 10 100
Live Example

Basically, say is not a function, it is a function template. You cannot get an address of a template with &.
Just change:
reallyAsync(&say, n, x)
to:
reallyAsync(&say<float>, n, x)
and it should work.

reallyAsync(&say, n, x)
say is a template. In C++, you can't take an address of a template. This is a meaningless proposition.
It is important to understand the difference between a template, and a template instance. A template is nothing more than a specification, of sorts. It doesn't exist in any real or meaningful term. And the address-of operator can only work with real, actual objects, that exist somewhere, in some-fashion.
To eliminate the compilation error, you'll have to instantiate the template, turning it into something tangible:
reallyAsync(&say<float>, n, x);
From your point of view this may not be ideal, and defeats the purpose of template functions. There's probably a better, different way to do whatever you're really trying to accomplish, that does not require explicit template instantiation.

Related

Is it possible to pass static function as template argument without adding new function argument?

One can pass callback to other function using template to abstract from real callback type:
float foo(int x, int y) {return x*y;}
template<class F>
void call_it(F f, int a, int b)
{
f(a,b);
}
There is a cost of passing f as an argument and calling it indirectly. I wonder if, in case f is a static function it is possible to pass it somehow to template function "directly", without adding a callable to the function argument list, so that the call could be bound statically.
I see the analogy to passing an integer value as template argument. It doesn't require adding any new function arguments because it passes the integer just as immediate value into the function code:
template<int X> int foo(int y) {return X+y;}
Here is a non-working code presenting what I'd like to achieve:
template<class F>
void call_it(int a, int b)
{
F(a,b); // Assume that F is a static function and can be called directly
}
Is there any way to achieve it?
You can use a non-type template parameter. To still allow all kinds of callables you can use auto:
#include <iostream>
struct foo {
static float bar(int a,int b){
std::cout << "foo: " << a << " " << b;
return a + b;
}
};
template <auto f>
float call_it(int a,int b){
return f(a,b);
}
int main() {
call_it<&foo::bar>(1,2);
}
or without auto:
template <float (*f)(int,int)>
float call_it(int a,int b){
return f(a,b);
}
Quite simple:
float foo(int x, int y) {return x*y;}
template<auto f>
auto call_it(int a, int b)
{
return f(a,b);
}
int main()
{
std::cout << "ret val: " << call_it<foo>(1,2) << std::endl;
}
It is easy as you can use a non type template parameter. You can specify it fully with the type or more easy by using auto. The last has the problem that you can pass everything and the failure will be reported late when you call the non type template parameter. Maybe using a concept which checks for call ability is the best approach.

How to use generic function in c++?

I have written this code in which if I uncomment the 2nd last line I get error - "template argument deduction/substitution failed: ". Is it because of some limit to generic functions in C++? Also my program doesn't print floating answer for the array b. Is there anything I can do for that? (sorry for asking 2 questions in single post.)
P.S: I have just started learning C++.
#include <iostream>
using namespace std;
template <class T>
T sumArray( T arr[], int size, T s =0)
{
int i;
for(i=0;i<size;i++)
{ s += arr[i];
}
return s;
}
int main()
{
int a[] = {1,2,3};
double b[] = {1.0,2.0,3.0};
cout << sumArray(a,3) << endl;
cout << sumArray(b,3) << endl;
cout << sumArray(a,3,10) << endl;
//cout << sumArray(b,3,40) << endl; //uncommenting this line gives error
return 0;
}
EDIT 1: After changing 40 to 40.0, the code works. Here is the output I get:
6
6
16
46
I still don't get the floating answer in 2nd case. Any suggestion ?
The reason is that compiler can not deduce the type for T.
How it should understand what T is for your last example? The type of the first argument (b) is double[], while it is T[] in the function definition. Therefore it looks like that T should be double. However, the type of the third argument (40) is int, so it looks like T should be int. Hence the error.
Changing 40 to 40.0 makes it work. Another approach is to use two different types in template declaration:
#include <iostream>
using namespace std;
template <class T, class S = T>
T sumArray( T arr[], int size, S s =0)
{
int i;
T res = s;
for(i=0;i<size;i++)
{ res += arr[i];
}
return res;
}
int main()
{
int a[] = {1,2,3};
double b[] = {1.0,2.0,3.1};
cout << sumArray(a,3) << endl;
cout << sumArray(b,3) << endl;
cout << sumArray(a,3,10) << endl;
cout << sumArray(b,3,40) << endl; //uncommenting this line gives error
return 0;
}
Note that I had to cast s to T explicitly, otherwise the last example will lose fractional part.
However, this solution will still not work for sumArray(a,3,10.1) because it will cast 10.1 to int, so if this is also a possible use case, a more accurate treatment is required. A fully working example using c++11 features might be like
template <class T, class S = T>
auto sumArray(T arr[], int size, S s=0) -> decltype(s+arr[0])
{
int i;
decltype(s+arr[0]) res = s;
...
Another possible improvement for this template function is auto-deduction of array size, see TartanLlama's answer.
sumArray(b,3,40)
The type of 40 is int, but the type of b is double[3]. When you pass these in as arguments, the compiler gets conflicting types for T.
A simple way to fix this is to just pass in a double:
sumArray(b,3,40.0)
However, you would probably be better off allowing conversions at the call site by adding another template parameter. You can also add one to deduce the size of the array for you so that you don't need to pass it explicitly:
template <class T, class U=T, std::size_t size>
U sumArray(T (&arr) [size], U s = 0)
The U parameter is defaulted to T to support the default value for s. Note that to deduce the size of the array, we need to pass a reference to it rather than passing by value, which would result in it decaying to a pointer.
Calling now looks like this:
sumArray(b,40)
Live Demo
In
template <class T>
T sumArray( T arr[], int size, T s =0)
^ ^
Both (deducible) T should match.
In sumArray(b, 3, 40), it is double for the first one, and int for the second one.
There is several possibilities to fix problem
at the call site, call sumArray(b, 3, 40.0) or sumArray<double>(b, 3, 40);
Use extra parameter:
template <typename T, typename S>
auto sumArray(T arr[], int size, S s = 0)
Return type may be T, S, or decltype(arr[0] + s) depending of your needs.
make a parameter non deducible:
template <typename T> struct identity { using type = T;};
// or template<typename T> using identity = std::enable_if<true, T>;
template <typename T>
T sumArray(T arr[], int size, typename identity<T>::type s = 0)
Should be
sumArray(b,3,40.0)
so, T will be deduced to double. In your code it's int.
Another option when deduction fails is to explicitly tell the compiler what you mean:
cout << sumArray<double>(b,3,40) << endl;
The compiler does not know whether T should be int or double.
You might want to do the following, in order to preserve the highest precision of the types passed:
template <class T, class S>
std::common_type_t <T, S> sumArray (T arr [], std::size_t size, S s = 0)
{
std::common_type_t <T, S> sum = s;
for (std::size_t i = 0; i != size; ++i)
{
sum += arr[i];
}
return sum;
}
The function you are writing, however, already exists. It's std::accumulate:
std::cout << std::accumulate (std::begin (b), std::end (b), 0.0) << std::endl;
Templates only accept one type of data, for example if you send an array of double, then the runtime will deduce :
Template = double[]
so every time he will see it he will expect an array of doubles.
sumArray(b,3,40) passes "b" (which is an array of doubles) but then you pass "40" which the runtime cannot implicitly convert to double.
So the code
sumArray(b,3,40.0)
will work

How to unambiguously refer to function with template overloads

Suppose I have the following definitions:
int f(int ) { return 1; } // a)
template<typename T> int f(T x) { return 2; } // b)
I understand that if I call f, e.g. f(1), the non-template overload a) will be preferred, but is there a way to unambiguously refer to a)? For instance, I can use f<int> to refer to b) unambiguously.
As an example of why this would be useful, consider the following function:
template<typename Func, typename T> void print_result(Func f, T arg)
{
std::cout << f(arg) << std::endl;
}
If I try to use it on f, e.g, print_result(f,1), I get a compilation error (the compiler does not know which f I mean). I can use print_result(f<int>,1) to tell it to use b), but how do I tell it to use a) ?
I found I can use print_result(static_cast<int (*)(int)>(f), 1), but this feels hacky and is cumbersome. Is there a better way?
use template specialization:
template<>
int f<int>(int x ) { return 1; } // a)

How to create and use a non type template in c++ and where would it be used

i am trying to learn templates in c++. Can someone please explain why sq() works and add() does not? How can add() be fixed? What is use of non type templates?
template <typename T>
inline T sq (const T& x)
{
return x*x;
}
template <int*>
inline int add(int* x)
{
return (*x)*2;
}
int main() {
int x = 2;
cout<<"Square(2): "<<sq(2)<<" Add(2): "<<add(&x)<<endl;
return 0;
}
Even after modifying the above example as below, it would still Not work
template <typename T>
inline T sq (const T& x)
{
return x*x;
}
template <int>
inline int add(int x)
{
return x+x;
}
int main() {
cout<<"Square(2): "<<sq(2)<<" Add(2): "<<add(2)<<endl;
return 0;
}
I'm not quite sure what you're asking, but you could use a non-type template parameter to, for example, define a function template that adds any compile-time constant to its argument:
template <int N>
inline int add(int x)
{
return x + N;
}
int main()
{
std::cout << add<3>(2) << std::endl; // prints 5
std::cout << add<4>(2) << std::endl; // prints 6
}
To answer your specific question about why sq(2) compiles but add(&x) doesn't: type parameters of function templates can be deduced from the function arguments. So sq(2) is equivalent to sq<int>(2). Non-type parameters can't be deduced, so you have to provide one. In the case of a pointer parameter, the argument must be a pointer to a variable with external linkage, so the following should compile:
int global;
int main() {
int local = 2;
std::cout << add<&global>(&local) << std::endl;
}
The classical example of using a non-type template parameter for a
function template would be something like:
template <typename T, size_t N>
T*
end( T (&array)[N] )
{
return array + N;
}
In this case, if you write something like:
int a[] = { 1, 2, 3, 4 };
int* endPtr = end(a);
, the compiler can deduce the length of the array for you.
Your add function doesn't use any template-related features. It would work fine as a non-template function. I can't make out what you're really trying to do so unfortunately I can't even guess at a fix for your real problem.
EDIT: If from your title I infer you want to know about non-type template parameters, what about a totally incomplete array example:
template <typename T, int length>
struct Array
{
T array_data_[length];
};
As it was said, what you are trying to do is some how pointless, the only case when you might want to provide the exact parameter type in templates is for template functions overloading. for instance when you want to make some function work in different manner for some special type this is called template specialization. For more details you might want to visit
:
Function template specialization format
The point of templates is that so you dont have to define a specific datatype in the function or class.
Look at T add (const T& x) . There is no datatype in here, just a big T . That's due to that templates can assume the identity of any datatype, int, double, char or whatever you throw at it.
#include <iostream>
using namespace std;
template <typename T>
inline T sq (const T& x)
{
return x*x;
}
template <typename T>
inline T add (const T& x)
{
return x+x;
}
template <typename T>
inline T divide (const T& x, const T& y)
{
return x/y;
}
int main()
{
int x = 3;
cout<<"int \n";
cout<<"Square(3) : "<<sq(x)<<" \n";
cout<<"Add(3) : "<<add(x)<<" \n";
double y=3.00;
cout<<"\ndouble \n";
cout<<"Square(3) : "<<sq(y)<<" \n";
cout<<"Add(3) : "<<add(y)<<" \n";
double v=3.00;
double w=2.00;
cout<<"\ndouble \n";
cout<<"Square(3) : "<<sq(v)<<" \n";
cout<<"Add(3) : "<<add(v)<<" \n";
cout<<"divide(3/2) : "<<divide(v,w)<<" \n";
cout<<"\n \n";
return 0;
}

Function passed as template argument

I'm looking for the rules involving passing C++ templates functions as arguments.
This is supported by C++ as shown by an example here:
void add1(int &v) { v += 1 }
void add2(int &v) { v += 2 }
template <void (*T)(int &)>
void doOperation()
{
int temp = 0;
T(temp);
std::cout << "Result is " << temp << std::endl;
}
int main()
{
doOperation<add1>();
doOperation<add2>();
}
Learning about this technique is difficult, however. Googling for "function as a template argument" doesn't lead to much. And the classic C++ Templates The Complete Guide surprisingly also doesn't discuss it (at least not from my search).
The questions I have are whether this is valid C++ (or just some widely supported extension).
Also, is there a way to allow a functor with the same signature to be used interchangeably with explicit functions during this kind of template invocation?
The following does not work in the above program, at least in Visual C++, because the syntax is obviously wrong. It'd be nice to be able to switch out a function for a functor and vice versa, similar to the way you can pass a function pointer or functor to the std::sort algorithm if you want to define a custom comparison operation.
struct add3 {
void operator() (int &v) {v += 3;}
};
...
doOperation<add3>();
Pointers to a web link or two, or a page in the C++ Templates book would be appreciated!
Yes, it is valid.
As for making it work with functors as well, the usual solution is something like this instead:
template <typename F>
void doOperation(F f)
{
int temp = 0;
f(temp);
std::cout << "Result is " << temp << std::endl;
}
which can now be called as either:
doOperation(add2);
doOperation(add3());
See it live
The problem with this is that if it makes it tricky for the compiler to inline the call to add2, since all the compiler knows is that a function pointer type void (*)(int &) is being passed to doOperation. (But add3, being a functor, can be inlined easily. Here, the compiler knows that an object of type add3 is passed to the function, which means that the function to call is add3::operator(), and not just some unknown function pointer.)
Template parameters can be either parameterized by type (typename T) or by value (int X).
The "traditional" C++ way of templating a piece of code is to use a functor - that is, the code is in an object, and the object thus gives the code unique type.
When working with traditional functions, this technique doesn't work well, because a change in type doesn't indicate a specific function - rather it specifies only the signature of many possible functions. So:
template<typename OP>
int do_op(int a, int b, OP op)
{
return op(a,b);
}
int add(int a, int b) { return a + b; }
...
int c = do_op(4,5,add);
Isn't equivalent to the functor case. In this example, do_op is instantiated for all function pointers whose signature is int X (int, int). The compiler would have to be pretty aggressive to fully inline this case. (I wouldn't rule it out though, as compiler optimization has gotten pretty advanced.)
One way to tell that this code doesn't quite do what we want is:
int (* func_ptr)(int, int) = add;
int c = do_op(4,5,func_ptr);
is still legal, and clearly this is not getting inlined. To get full inlining, we need to template by value, so the function is fully available in the template.
typedef int(*binary_int_op)(int, int); // signature for all valid template params
template<binary_int_op op>
int do_op(int a, int b)
{
return op(a,b);
}
int add(int a, int b) { return a + b; }
...
int c = do_op<add>(4,5);
In this case, each instantiated version of do_op is instantiated with a specific function already available. Thus we expect the code for do_op to look a lot like "return a + b". (Lisp programmers, stop your smirking!)
We can also confirm that this is closer to what we want because this:
int (* func_ptr)(int,int) = add;
int c = do_op<func_ptr>(4,5);
will fail to compile. GCC says: "error: 'func_ptr' cannot appear in a constant-expression. In other words, I can't fully expand do_op because you haven't given me enough info at compiler time to know what our op is.
So if the second example is really fully inlining our op, and the first is not, what good is the template? What is it doing? The answer is: type coercion. This riff on the first example will work:
template<typename OP>
int do_op(int a, int b, OP op) { return op(a,b); }
float fadd(float a, float b) { return a+b; }
...
int c = do_op(4,5,fadd);
That example will work! (I am not suggesting it is good C++ but...) What has happened is do_op has been templated around the signatures of the various functions, and each separate instantiation will write different type coercion code. So the instantiated code for do_op with fadd looks something like:
convert a and b from int to float.
call the function ptr op with float a and float b.
convert the result back to int and return it.
By comparison, our by-value case requires an exact match on the function arguments.
Function pointers can be passed as template parameters, and this is part of standard C++
. However in the template they are declared and used as functions rather than pointer-to-function. At template instantiation one passes the address of the function rather than just the name.
For example:
int i;
void add1(int& i) { i += 1; }
template<void op(int&)>
void do_op_fn_ptr_tpl(int& i) { op(i); }
i = 0;
do_op_fn_ptr_tpl<&add1>(i);
If you want to pass a functor type as a template argument:
struct add2_t {
void operator()(int& i) { i += 2; }
};
template<typename op>
void do_op_fntr_tpl(int& i) {
op o;
o(i);
}
i = 0;
do_op_fntr_tpl<add2_t>(i);
Several answers pass a functor instance as an argument:
template<typename op>
void do_op_fntr_arg(int& i, op o) { o(i); }
i = 0;
add2_t add2;
// This has the advantage of looking identical whether
// you pass a functor or a free function:
do_op_fntr_arg(i, add1);
do_op_fntr_arg(i, add2);
The closest you can get to this uniform appearance with a template argument is to define do_op twice- once with a non-type parameter and once with a type parameter.
// non-type (function pointer) template parameter
template<void op(int&)>
void do_op(int& i) { op(i); }
// type (functor class) template parameter
template<typename op>
void do_op(int& i) {
op o;
o(i);
}
i = 0;
do_op<&add1>(i); // still need address-of operator in the function pointer case.
do_op<add2_t>(i);
Honestly, I really expected this not to compile, but it worked for me with gcc-4.8 and Visual Studio 2013.
In your template
template <void (*T)(int &)>
void doOperation()
The parameter T is a non-type template parameter. This means that the behaviour of the template function changes with the value of the parameter (which must be fixed at compile time, which function pointer constants are).
If you want somthing that works with both function objects and function parameters you need a typed template. When you do this, though, you also need to provide an object instance (either function object instance or a function pointer) to the function at run time.
template <class T>
void doOperation(T t)
{
int temp=0;
t(temp);
std::cout << "Result is " << temp << std::endl;
}
There are some minor performance considerations. This new version may be less efficient with function pointer arguments as the particular function pointer is only derefenced and called at run time whereas your function pointer template can be optimized (possibly the function call inlined) based on the particular function pointer used. Function objects can often be very efficiently expanded with the typed template, though as the particular operator() is completely determined by the type of the function object.
The reason your functor example does not work is that you need an instance to invoke the operator().
Came here with the additional requirement, that also parameter/return types should vary.
Following Ben Supnik this would be for some type T
typedef T(*binary_T_op)(T, T);
instead of
typedef int(*binary_int_op)(int, int);
The solution here is to put the function type definition and the function template into a surrounding struct template.
template <typename T> struct BinOp
{
typedef T(*binary_T_op )(T, T); // signature for all valid template params
template<binary_T_op op>
T do_op(T a, T b)
{
return op(a,b);
}
};
double mulDouble(double a, double b)
{
return a * b;
}
BinOp<double> doubleBinOp;
double res = doubleBinOp.do_op<&mulDouble>(4, 5);
Alternatively BinOp could be a class with static method template do_op(...), then called as
double res = BinOp<double>::do_op<&mulDouble>(4, 5);
EDIT
Inspired by comment from 0x2207, here is a functor taking any function with two parameters and convertible values.
struct BinOp
{
template <typename R, typename S, typename T, typename U, typename V> R operator()(R (*binaryOp )(S, T), U u, V v)
{
return binaryOp(u,v);
}
};
double subD(double a, int b)
{
return a-b;
}
int subI(double a, int b)
{
return (int)(a-b);
}
int main()
{
double resD = BinOp()(&subD, 4.03, 3);
int resI = BinOp()(&subI, 4.03, 3);
std::cout << resD << std::endl;
std::cout << resI << std::endl;
return 0;
}
correctly evaluates to double 1.03 and int 1
Edit: Passing the operator as a reference doesnt work. For simplicity, understand it as a function pointer. You just send the pointer, not a reference.
I think you are trying to write something like this.
struct Square
{
double operator()(double number) { return number * number; }
};
template <class Function>
double integrate(Function f, double a, double b, unsigned int intervals)
{
double delta = (b - a) / intervals, sum = 0.0;
while(a < b)
{
sum += f(a) * delta;
a += delta;
}
return sum;
}
.
.
std::cout << "interval : " << i << tab << tab << "intgeration = "
<< integrate(Square(), 0.0, 1.0, 10) << std::endl;