is there anyway pass function as template parameter? - c++

i have been working on a project and i need to know that is there anyway passing a function to template class? lets say i want this to perform sinus or cosinus function
#ifndef INTEGRAL_H
#define INTEGRAL_H
template<class F>
class Integral
{
public:
Integral( F func):f_(func){}
~Integral()=default;
Integral(){
int a,b,N;
double h=(b-a)/N;
sum=0.0;
for (size_t j=0; j<N;++j)
{
sum+=f_(a+j*h); // here i would like to perform sin(a+j*h) or cosinus or somethingelse
}
sum*=h;
}
double Sum(){return sum;}
private:
F f_;
double sum;
};
#endif // INTEGRAL_H

Your code works "as coded" (after a small fix in the constructor, unrelated to the question). But std::sin doesn't name a single function, and you can't pass it into Integral directly. The simplest way is to wrap it into a lambda:
Integral i([](auto arg) { return std::sin(arg); });
double value = i.Sum();
If your compiler doesn't support template argument deduction (available since C++17), you have to be more verbose:
auto my_sin = [](auto arg) { return std::sin(arg); };
Integral<decltype(my_sin)> i(my_sin);
double value = i.Sum();

This might help: Function passed as template argument
In the end, a function is nothing but an address to a particular place in memory which boils down to a simple number and that is something that the template system supports.
However, in your case I would recommend just passing an std::function object which is a glorified function pointer as a regular parameter to your function - omitting the need for a template (at least for this part of the functionality).

is there anyway pass function as template parameter?
Yes. Example:
template<return_type (template_argument_name)(argument_list)>
Another approach is to pass a callable type as template parameter, and invoke an object of that type. This is in fact what you've done in your example.

Related

Why could not deduce template argument when passing lambda instead of function pointer

I have a bubble-sort function that takes an array, a compare function, and a boolean that indicates if it should sorts the array upside-down. It is a template function that supports any data-type, and will deduce array size automatically.
When specifying the compare function, if I pass function pointer, the compiler will deduce the data type of array automatically, which is great. But if I pass a lambda instead, it will not deduce automatically. I have to specify the data type explicitly, or static_cast the lambda as fnCompare_t<double>.
What is the reason behind this? Because according to this post, as long as the lambda doesn't capture, it can be used like the plain-old function pointer, but it seems it is not always the case? How come it can be different in this case?
#include <iostream>
using namespace std;
template <typename T>
using fnCompare_t = int(*)(T const &, T const &);
template <typename T, size_t count>
inline void BubbleSort(
T(&array)[count],
fnCompare_t<T> fnCompare,
bool reverse)
{
cout << "TODO: Implement BubbleSort" << endl;
}
double doubleArray[] = {
22.3, 11.2, 33.21, 44.2, 91.2, 15.2, 77.1, 8.2
};
int CompareDouble(double const & a, double const & b)
{
return a > b ? 1 : a == b ? 0 : -1;
}
int main()
{
auto fnCompare = [](double const & a, double const & b) -> int {
return a > b ? 1 : a < b ? -1 : 0;
};
// compile OK:
BubbleSort(doubleArray, CompareDouble, false);
BubbleSort(doubleArray, static_cast<fnCompare_t<double>>(fnCompare), false);
BubbleSort<double>(doubleArray, fnCompare, false);
// compile error, could not deduce template argument:
//BubbleSort(doubleArray, fnCompare, false);
return 0;
}
The reason why is because you can't get an implicit conversion on a templated parameter when using deduction. The classic example is:
template <class T>
T min(T x, T y);
Calling this function as min(1, 3.0) will result in a failure. Because for both arguments, it tries to find a T to get a perfect match, and fails. If you specify the template parameter explicitly it can work: min<double>(1, 3.0). The same is true in your example, if you specify T explicitly it will work.
The idiomatic way to write the signature for your function is:
template <typename Iter, typename F>
inline void BubbleSort(
Iter b, Iter e,
F fnCompare,
bool reverse)
However, this discards the compile time length information. If you want to keep that, you can do:
template <typename T, size_t count, typename F>
inline void BubbleSort(
T(&array)[count],
F fnCompare,
bool reverse);
Though you should at least consider using std::array instead of a C style array which will make the signature a bit less ugly and has other benefits.
This may seem odd as we are not "verifying" the comparator having the correct signature, in the signature of our sort. But this is normal in C++, if the comparator is incorrect then it will fail at the point of usage and it will still be a compile time error. Note as well when you try to depend on a lambda implicitly converting into a function pointer, you are being unnecessarily restrictive: lambdas only convert into function pointers with identical signature. Even if the output of the lambda is implicitly convertible to the output of the function pointer, your lambda will not implicitly convert, even though the lambda can still be used!
As a final final note, it's usually better to pass functors because it's better for performance. Comparators are usually small functions and often will get inlined. But in your version, the comparator will not typically be inlined, in mine it will (because I preserve the original type of the lambda, and you do not).
You need to explicitly cast the lambda to a function pointer. There is no other way around it. But, instead of static_casting you can apply + to the lambda, which would trigger the function pointer conversion, as you can apply + to a pointer type:
BubbleSort(doubleArray, +fnCompare, false);
// ^^
// applying unary + invokes the function pointer conversion operator
The reason for why there is no implicit call to the conversion operator is that during overload resolution, the compiler will only consider templates that match perfectly (see this for more info). Because a lambda is not a function pointer, there cannot be a perfect match, and the overload is discarded.

Lambda as template function

I have a very strange problem. To keep things simple, lets say I want to have a function which takes 2 functions with the same declaration as arguments
template<typename Func>
void foo(Func a, Func b)
{
std::cout << "good";
}
To try things out I took putchar from cstdio, and created an identical function to match the putchar.
int myPutcharFunc(int)
{
return 0;
}
int main()
{
auto myPutcharLambda = [](int) -> int
{
return 0;
};
foo(putchar, myPutcharFunc); // okay
foo(putchar, myPutcharLambda); //deduced conflicting types for parameter 'Func' ('int (__attribute__((__cdecl__)) *)(int)' and 'main()::<lambda(int)>')
}
Now, the lambda does not want to compile (the key is I want to use lambda capture).
So lets add template specialization, because the programmer is wiser than the machine, right? :)
template<typename Func>
void foo(Func a, Func b)
{
std::cout << "good";
}
template<>
void foo(int(*)(int), int(*)(int))
{
std::cout << "good";
}
No luck, the same error - why?
But for some reason, when I comment out the template specialization:
//template<>
void foo(int(*)(int), int(*)(int))
{
std::cout << "good";
}
The code compiles. I obviously do not want to overload foo for EVERY set of function's arguments - thats what templates are for. Every step was tested both with msvc++ and g++. What am I doing wrong?
Two possibilities.
1: Just put + in front of the lambda:
foo(putchar, +myPutcharLambda);
That works because unary + expects an integer-like value, such as a pointer. Therefore, the lambda converts to a function pointer.
Ultimately a (non-capturing) lambda doesn't have the same type as a function pointer, even though it's willing to convert to a function pointer.
How is a compiler supposed to know which conversions are allowed to make two objects of the same type?
2: There is another option, making use of the fact that the ?: is willing to do some conversions, converting one type to another in some circumstances.
template<typename Func1, typename Func2>
void foo2(Func1 a, Func2 b)
{
using common_type = decltype(true?a:b); // or 'false', it doesn't matter
foo<common_type>(a,b);
}
Every lambda is a different type, so you'll need to have two different template parameters to get them
template<typename FuncA, typename FuncB>
void foo(FuncA a, FuncB b)
Types don't decay when deducing template types (SEE COMMENT FOR CORRECTION). So a lambda remains a lambda and doesn't decay to a function pointer. Same reason a string literal is deduced as a char[N] instead of a const char *.
With your second example using specialization, it doesn't want to use your specialization, since the lambda is not a function pointer. You can cast the Lambda to a function pointer and make it work: https://godbolt.org/g/ISgPci The trick you can do here is say +my_lambda because + is defined for pointers so it will force the non-capturing lambda to become a function pointer.
A lambda has its own type which can decay to a function pointer but not in the case of a template function match, it will for the real function as you found because of the implicit conversion.
In the case of matching to a template you need to disambiguate and explicitly instantiate foo with the type you want or convert the lambda to a function pointer.
foo<decltype(putchar)>(putchar, myPutcharLambda);
or
foo(putchar, +myPutcharLambda);

What does reference with a template type mean?

In the code that I try to understand I see constructs like this: ref<date>(entry). Can anybody, please, explain what it can mean.
I assume that we create a reference to the entry object but how date type is used. For example ref<date>(entry) and ref<location>(entry) will return different values. How does it work?
If you have using namespace std; and are including the <functional> header, this is referring to the std::ref function.
std::ref is a function that will create a std::reference_wrapper wrapping the object you pass. The whole point of std::ref is that you don't have to give the template argument because it can be deduced. So if you want a reference to entry, then you should just do:
std::ref(entry)
It's a convenience function that saves you having to type redundant type names when creating a std::reference_wrapper. If you do it manually, you would have to do:
std::reference_wrapper<date>(entry)
That's because std::reference_wrapper is a template class and template class parameters cannot be deduced in this way.
The std::ref function template is used to create an std::reference_wrapper for a certain object. This allows passing an object by reference to a function template even though the function template takes the corresponding argument by value:
For instance:
template<typename T>
void foo(T t)
{
t = 42;
}
int x = 0;
foo(std::ref(x));
std::cout << x; // Will print 42
Notice, that function foo() above is quite a stupid function, and I wrote it just for illustrative purpose. More often, you will find std::ref or std::cref being used in combination with std::bind, which by default creates a copy of the arguments you provide:
template<typename T>
void bar(T v1, T& v2)
// ^
// Second argument accepted by reference this time...
{
v2 = v1 + 42;
}
int x = 0;
auto f = std::bind(bar, 0, ref(x));
// ^^^
// ...but without this, a copy of x would be created!
f(x);
std::cout << x; // Will print 42
Also notice, that you do not normally specify a template argument explicitly for std::ref or std::cref, but you rather let the function template deduce it.

C++ how to pass method as a template argument

Suppose I have a class X:
class X {
// ...
size_t hash() const { return ...; }
};
I would like to create a std::tr1::unordered_map<X, int, HashFn> where I want to pass in
X::hash() as HashFn. I know I can declare my own functor object. I feel that
there should be a way to do this by directly passing a pointer to X::hash().
Is there?
No; as you've shown it, you need a small utility struct:
#include <functional>
template<typename T, std::size_t (T::*HashFunc)() const = &T::hash>
struct hasher : std::unary_function<T, std::size_t>
{
std::size_t operator ()(T const& t) const
{
return (t.*HashFunc)();
}
};
Then you can create an unordered_map like so:
std::tr1::unordered_map<X, int, hasher<X> > m;
No, there isn't. The reason is that whatever is used as your HashFn must take a single argument which is a const reference to an object in the container. X::hash takes a single argument which is a const pointer to an object in the container (the this pointer is an implicit first argument in this case), so using that function by it self is not possible.
You probably use some bind magic, using boost::lambda and boost::bind. I'm not exactly sure how, but it would probably look something like this:
boost::bind(&X::hash, &_1);
Which creates a function object which will call X::hash with a pointer.
size_t hash() const { return ...;}
A function which calculates hash value takes one parameter of type Key which your function doesn't take. Hence its signature is wrong to begin with.
Since you want to implement a function, rather than a functor, here is how it should be done:
size_t hash(const KeyType &key)
{
return /*calculate hash and return it*/;
}
Make it static member function and pass it as X::hash or make it a free function, is your choice.
You can't directly, but you can wrap it. The easy way to do so is to use boost::mem_fn(), or the standard equivalents if your compiler supports them: tr1::mem_fn() (from TR1) or std::mem_fn() (from C++11).
EDIT: Actually it's not so simple. mem_fn() will work fine for a function parameter, but since its return type is unspecified it's difficult to use as a template parameter. If you have C++11 support you could use decltype to find the type; otherwise you're probably best off writing your own function object as you mentioned.

c++ deduction of "non type pointer to function" class template parameters

Consider a template class like:
template<typename ReturnType, ReturnType Fn()>
class Proxy
{
void run()
{
ReturnType ret = Fn();
// ... do something ...
}
};
// and a functions
int fn1() { return 5; }
float fn2() { return 5; }
This can be instantiated by using:
Proxy<int, &fn1> p1;
But explicitly declaring the return value type seems needless. What I am trying to achieve is something like:
someProxyInstantation<&fn1> p1;
someProxyInstantation<&fn2> p2;
Unfortunately, I'm no c++ expect and this seems like a hidden corner of the language (at least for me).
If I could just get from the pointer to the function to its type - something like:
std::tr1::result_of<&fn>::type // Error 1 error C2923: 'std::tr1::result_of' : 'fn1' is not a valid template type argument for parameter '_Fty'
the error makes sense since the parameter is not a "type" at all
C++0x has the decltype(&fn1) but that is years away.
Any way of doing this in C++03 (+ tr1)?
Restrictions:
- I don't want to pass the functor, f1 and f2 have to remain global functions that have a return value (can't move it to parameter).)
This isn't possible in C++03. If you want to pass a function pointer as a non-type parameter, the compiler has to know the type of the parameter. So you have to provide the missing pieces (in this case, the return type). You can give the proxy the function pointer as a value at runtime, and provide it with the type of it as the only argument. Then you could write a generator function for you that does this job:
template<typename T>
Proxy<T> make_proxy(T t) { return Proxy<T>(t); }
Sadly, in current C++, you still have to give it the type in order to assign to a automatic variable:
Proxy<int(*)()> p = make_proxy(&fn1);
You can't use auto p = make_proxy(&fn1); yet. Note that if you want to use a function type on the left side, you have to change the generator function to provide not a function pointer type:
template<typename T>
Proxy<typename boost::remove_pointer<T>::type> make_proxy(T t) {
return Proxy<typename boost::remove_pointer<T>::type>(t);
}
Now you can do
Proxy<int()> p = make_proxy(&fn1);
using the proxy, you can now just do
doSomething(make_proxy(&fn1));
And if doSomething is templated or otherwise polymorphic, it will not require you to know the exact type of the function.