default value for template function, functional parameter - c++

template<typename Iterator, typename typename Comparator = std::less<typename std::iterator_traits<Iterator>::value_type>>
static void sort(Iterator begin, Iterator end, Comparator cmp = Comparator())
{
...
}
I have the following template function:
template<typename func>
static void sort_test(func sort)
{
...
sort(somevector.begin(), somevector.end());
...
}
int main()
{
sort_test(&sort<vector<int, allocator<int>>::iterator>);
return 0;
}
error C2198: 'void (__cdecl *)(iterator,iterator,std::less)' : too few arguments for call
If I try to bypass the default argument by providing it:
template<typename func>
static void sort_test(func sort)
{
...
sort(somevector.begin(), somevector.end(), std::less<int>);
...
}
int main()
{
sort_test(&sort<vector<int, allocator<int>>::iterator>,
std::less<int>);
return 0;
}
error C2275: 'std::less' : illegal use of this type as an expression

Default arguments are not part of a function's signature, so when you go through a pointer to function indirection, as you're doing in the first example, that information is lost. If you call your sort function directly within main with 2 iterator arguments, the code will compile.
In the second example you're getting a compilation error because you're trying to pass a type, instead of an instance, to sort
sort(somevector.begin(), somevector.end(), std::less<int>());
You also have an extra typename in the template parameter list for sort
template<typename Iterator, typename typename Comparator = std::less<typename std::iterator_traits<Iterator>::value_type>>
// ^^^^^^^^

Related

C++ template function pointer type deduction

I have the following code
using my_map_t = std::map<int, Object<double>>;
using my_map_iterator_t = my_map_t::iterator;
template <typename FWD, typename Func>
void inner(my_map_t& map, int key, FWD&& obj, Func emplacer) {
emplacer(map, key, std::forward<FWD>(obj));
}
my_map_t map;
template <typename FWD>
void outer(my_map_t& map, int key, FWD&& obj)
{
auto lambda = [](my_map_t& m, int k, FWD&& o) {
m.emplace(k, std::forward<FWD>(o));
};
inner(map, key, std::forward<FWD>(obj), lambda);
}
which compiles painlessly. So this means that he deduce automatically the template argument of inner function.
However, if I introduce a function pointer I need to specify the function pointer template argument, otherwise the compiler complaints
using my_map_t = std::map<int, Object<double>>;
using my_map_iterator_t = my_map_t::iterator;
template <typename FWD, typename Func>
void inner(my_map_t& map, int key, FWD&& obj, Func emplacer) {
emplacer(map, key, std::forward<FWD>(obj));
}
template <typename FWD, typename Func>
void(*fp)(my_map_t&, int, FWD&&, Func) = &inner;
my_map_t map;
template <typename FWD>
void outer(my_map_t& map, int key, FWD&& obj)
{
auto lambda = [](my_map_t& m, int k, FWD&& o) {
m.emplace(k, std::forward<FWD>(o));
};
(*fp<FWD, decltype(lambda)>)(map, key, std::forward<FWD>(obj), lambda);
}
Why in the case of function pointer the argument deduction is not working any more?
Did I make some mistake? Is there a way to achieve a better syntax?
NOTE ADDED
I need to use function pointer because I have some function with the same signature of inner. Let us call them inner1, inner2 and inner3. They are called by some outer function
void outer(...) {
if(...) {
inner1(...)
} else if (...) {
inner2(...)
} else {
inner3(...)
}
some_long_task(...)
}
Now in my case the outer function is called cyclically. The checks in the ifs can be time consuming and they are independent of the argument of outer function. I was thinking while the some_long_task is being executed, to set up a function pointer to the right function inner1, inner2 or inner3 exploiting some cpu parallelism, so that, the the new cycle begin, I do not have to waste time doing the if check.
template <typename FWD, typename Func>
void(*fp)(my_map_t&, int, FWD&&, Func) = &inner;
is not a normal function pointer. It is what's called a variable template. When you have a variable template, in order to refer to a specific instantiation, you must specify the template parameters. To demonstratre that, consider
template <typename T>
constexpr T pi = T(3.1415926535897932385L);
You can't just do cout << pi because we don't know which pi to use. The same occurs with
(*fp<FWD, decltype(lambda)>)(map, key, std::forward<FWD>(obj), lambda);
Here fp needs the <FWD, decltype(lambda)> so the compiler can know which specific fp instance to refer to. It has to do this even before it evaluates the function call because it needs to check the parameters against the function.
What we would need to not have to specify the parameter is a future like CTAD but would work for function pointer variable temapltes.

Check if function return type is the same as an STL container type value

I'm working with a struct that takes a generic function and a generic STL container, but i want to make a type check in the constructor in order to raise an error if the return type of the function is different from the constructor type: is it possible to do something like this without changing the template?
template<class Function, class Container>
struct task{
Function f;
Container& c;
task(Function func, Container& cont):f(func), c(cont){
//error if mismatch between container type and function return type
}
};
int multiply(int x){ return x*10; }
int main(){
vector<int> v;
int c=10;
auto stateless = [](float x){ return x*10;};
auto stateful = [&c](int x){ return x*c;};
task t(multiply, v); //SAME TYPE: OKAY!
task tt(stateless, v); //TYPE MISMATCH: ERROR!
return 0;
}
thank you for your help
Not sure to understand completely but... if the "generic funcion" isn't a generic-lambda or a template operator() in a class/struct... you tagged C++17 so you can use deduction guides so you can deduce the type returned from the function using std::function's deduction guides.
Something as
decltype(std::function{std::declval<Function>()})::result_type
For the value type of the container is usually available the value_type type.
So, defining a couple of using types inside the body of the struct, you can write
template <typename F, typename C>
struct task
{
using rtype = typename decltype(std::function{std::declval<F>()})::result_type;
using vtype = typename C::value_type;
// ...
task (F func, C & cont) : f{func}, c{cont}
{ static_assert( std::is_same<rtype, vtype>{} );}
};
But observe that the static_assert() inside the constructor use only elements that aren't specific of the constructor.
This way, if you have to develop (by example) ten constructors, you have to write ten times the same static_assert() inside the ten constructors bodies.
I suggest to place the static_assert() inside the body of the struct so you have to write it only one time.
I mean
template <typename F, typename C>
struct task
{
using rtype = typename decltype(std::function{std::declval<F>()})::result_type;
using vtype = typename C::value_type;
static_assert( std::is_same<rtype, vtype>{} );
// ...
};
The following is a full compiling example
#include <vector>
#include <functional>
template <typename F, typename C>
struct task
{
using rtype = typename decltype(std::function{std::declval<F>()})::result_type;
using vtype = typename C::value_type;
static_assert( std::is_same<rtype, vtype>{} );
F f;
C & c;
task (F func, C & cont) : f{func}, c{cont}
{ }
};
int multiply (int x)
{ return x*10; }
int main ()
{
std::vector<int> v;
int c=10;
auto stateless = [](float x){ return x*10;};
auto stateful = [&c](int x){ return x*c;};
task t1(multiply, v); // compile
task t2(stateful, v); // compile
task t3(stateless, v); // compilation error
}
But remember: this function doen't works with generic-lambdas.
In that case I don't know how to solve the problem and I suppose isn't solvable at all without knowing the type of the input parameters.
You can use static_assert with std::is_same to check type equality at compile time.
If your lambda function always takes no parameters, you can use decltype(f())
to get the function return type, else you will need
std::result_of / std::invoke_result or a function traits implementation.
#include <type_traits>
template<class Function, class Container>
struct task{
Function f;
Container& c;
task(Function func, Container& cont):f(func), c(cont){
static_assert(
std::is_same<
decltype(f()), // type of function return value
typename Container::value_type // type of values stored in container
>::value,
"incompatible function" // error message
);
}
};
I see no way to go ahead without using any kind of helper template to determine the parameter list here!
So the following solution is still based on Is it possible to figure out the parameter type and return type of a lambda?
For having function pointers and callable classes like lambdas, it only needs an specialized template instance.
template <typename CLASS>
struct function_traits_impl
: public function_traits_impl<decltype(&CLASS::operator())>
{};
template <typename CLASS, typename RET, typename... ARGS>
struct function_traits_impl< RET(CLASS::*)(ARGS...) const>
{
using args_type = std::tuple<ARGS...>;
using ret_type = RET;
};
template <typename CALLABLE > struct function_traits: public function_traits_impl< CALLABLE >{};
template< typename RET, typename... ARGS >
struct function_traits< RET(*)(ARGS...) >
{
using args_type = std::tuple<ARGS...>;
using ret_type = RET;
};
template < typename CLASS, typename CONTAINER, typename RET, typename ... ARGS> struct task;
template< typename CLASS, typename CONTAINER, typename RET, typename ... ARGS >
struct task< CLASS, CONTAINER, RET, std::tuple<ARGS...> >
{
using FUNC = std::function< RET(ARGS...)>;
FUNC func;
CONTAINER cont;
task( FUNC _func, CONTAINER& _cont): func{_func}, cont{_cont}
{
static_assert(
std::is_same<
//decltype( func( std::declval<PARMS>()...) ), // but is already known from given template parms!
RET,
typename CONTAINER::value_type
>::value,
"wrong return type, did not match with container type"
);
}
};
template <typename FUNC, typename CONTAINER >
task(FUNC, CONTAINER) -> task< FUNC, CONTAINER, typename function_traits<FUNC>::ret_type, typename function_traits<FUNC>::args_type>;
int Any( int ) { return 0; }
float WrongAny( int, int ) { return 1.1; }
int main()
{
std::vector<int> v;
//task t1{ [](int, int)->float { return 0; } , v}; // fails with assert as expected
task t2{ [](int, int)->int { return 0; } , v}; //Works!
task t3{ &Any , v}; // Works
//task t4{ &WrongAny, v }; fails as expected
}
This solution simply uses user defined deduction guide to forward the found parms from the trait which is helpful as you also use c++17.
Hint:
Generic lambdas cant be used, because if the parameters to call the lambda are unknown, how you could determine the parameters "automatically". It is quite easy to specify the parameters with the call and get the return type, but passing an generic lambda or an object with overloaded call operator needs to specify which of the functions/methods are should be used. So if you need generic lambdas or overloaded methods in class objects simply specify params manually! There can't be a trick in any language which allows you to give a set of optional calls and determine automatically which call should be used if no other information is available. As said: If params for the call are present, simply use them!
Remark:
If you use this solution, you only get a single template instance for all calls with same parameter set to the function call which may save some memory ;) But it uses a std::function to store teh callable which takes some runtime... You have now two solutions which differs in the results but both are usable ;)

Template variadic function in template class won't compile

I'm trying to write a function for a template class which takes in a parameter that is a function pointer for a member class inside the private data of the big class. When you call that member, it calls that function on smaller class. (Confusing right?) To demonstrate, I have a non-working example here:
#include <vector>
#include <iostream>
using namespace std;
template <typename T, typename C>
struct MyClass {
template <typename F, typename... A>
auto call_me(F func, A... args) { // pass in the function we want to call
return (mContainer.*func) (args...); // call the function supplied by
// the parameter on the private member data
}
C mContainer; // this will be private in my actual code
};
int main() {
MyClass<int, std::vector<int> > test;;
cout << test.call_me(&std::vector<int>::size) << endl; // works
test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4); // doesn't work
return 0;
}
Please note that this isn't my actual code but a small example of what I'm trying to do. As you can see, I'm trying to call the size member function of the 'Private' (I have kept it public here for demonstration) vector class inside MyClass. This only works whenever I have no parameters for the compiler to unpack, but when I try to do the insert function (which has parameters to unpack), the compiler gives me an error of:
.\template.cpp: In function 'int main()':
.\template.cpp:24:71: error: no matching function for call to 'MyClass<int, std::vector<int> >::call_me(<unresolved overloaded function type>, std::vector<int>::iterator, int)'
test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4);
^
.\template.cpp:10:10: note: candidate: template<class F, class ... A> auto MyClass<T, C>::call_me(F, A ...) [with F = F; A = {A ...}; T = int; C = std::vector<int>]
auto call_me(F func, A... args) { // pass in the function we want to call
^~~~~~~
.\template.cpp:10:10: note: template argument deduction/substitution failed:
.\template.cpp:24:71: note: couldn't deduce template parameter 'F'
test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4);
This is the same error I'm getting in my actual production code, calling the variadic function with no parameters to unpack works, but if I give more than that, I get the same error message. This is my first real attempt to use Variadic templates, so any recommendation and help will be appreciated.
The problem here is that insert is an overloaded function. The compiler is not doing to try and resolve what overload you want in template argument deduction as there is no way for it to know. You have to cast the function to the type of the overload you want to use in order to give it a type. That would look like
using insert_func_t = std::vector<int>::iterator(std::vector<int>::*)(std::vector<int>::const_iterator, const int&);
test.call_me(static_cast<insert_func_t>(&std::vector<int>::insert), test.mContainer.begin(), 4);
In general it is
static_cast<return_type(class_name::*)(function_parameters)>(&class_name::function_name)
Another option would be to change the function a little and take a lambda that expresses what you want done. That would look like
template <typename T, typename C>
struct MyClass {
template <typename F, typename... A>
auto call_me(F func, A... args) { // pass in the function we want to call
return func(mContainer, args...); // call the function supplied by
// the parameter on the private member data
}
C mContainer; // this will be private in my actual code
};
int main() {
MyClass<int, std::vector<int> > test;;
test.call_me([](auto& container, auto... args){ container.insert(args...); }, test.mContainer.begin(), 4);
return 0;
}
Basically you cannot take address of an unresolved overloaded function, because the compiler won't be able to choose the right function entry point address. During normal function call the compiler resolves overloaded function, but with templates like yours or std::bind() this won't work, because the parameters are used to call the template function, not the function you want to take address of.
You can manually resolve the overload like this:
using ftype = std::vector<int>::iterator(std::vector<int>::*)
(std::vector<int>::const_iterator, const std::vector<int>::value_type&);
test.call_me((ftype)(&std::vector<int>::insert), test.mContainer.begin(), 4); // works
It's easier to deal in function objects when doing this kind of thing. It offloads the problem of method overloads to the compiler.
Lambdas also work (they're function objects):
#include <vector>
#include <iostream>
template <typename T, typename C>
struct MyClass {
template <typename F, typename... A>
auto call_me(F func, A&&... args) -> decltype(auto)
{ // pass in the function we want to call
return func(mContainer, std::forward<A>(args)...); // call the function supplied by
// the parameter on the private member data
}
C mContainer; // this will be private in my actual code
};
/*
* It's often easier to deal in function objects
*/
struct insert
{
template<class Container, class...Args>
decltype(auto) operator()(Container& cont, Args&&...args) const
{
return cont.insert(std::forward<Args>(args)...);
}
};
struct size
{
template<class Container, class...Args>
decltype(auto) operator()(Container& cont) const
{
return cont.size();
}
};
int main() {
MyClass<int, std::vector<int> > test;;
std::cout << test.call_me(size()) << std::endl; // works
test.call_me(insert(), test.mContainer.begin(), 4); // doesn't work
// or lambdas
auto insert2 = [](auto& container, auto&&...args) -> decltype(auto)
{
return container.insert(std::forward<decltype(args)>(args)...);
};
test.call_me(insert2, test.mContainer.begin(), 5);
return 0;
}

C++ template type deduction fails for lambda to function pointer conversion [duplicate]

I'm learning C++, and I'm trying to implement a binary search function that finds the first element for which a predicate holds. The function's first argument is a vector and the second argument is a function that evaluates the predicate for a given element. The binary search function looks like this:
template <typename T> int binsearch(const std::vector<T> &ts, bool (*predicate)(T)) {
...
}
This works as expected if used like this:
bool gte(int x) {
return x >= 5;
}
int main(int argc, char** argv) {
std::vector<int> a = {1, 2, 3};
binsearch(a, gte);
return 0;
}
But if I use a lambda function as a predicate, I get a compiler error:
search-for-a-range.cpp:20:5: error: no matching function for call to 'binsearch'
binsearch(a, [](int e) -> bool { return e >= 5; });
^~~~~~~~~
search-for-a-range.cpp:6:27: note: candidate template ignored: could not match 'bool (*)(T)' against '(lambda at
search-for-a-range.cpp:20:18)'
template <typename T> int binsearch(const std::vector<T> &ts,
^
1 error generated.
The above error is generated by
binsearch(a, [](int e) -> bool { return e >= 5; });
What's wrong? Why is the compiler not convinced that my lambda has the right type?
Your function binsearch takes a function pointer as argument. A lambda and a function pointer are different types: a lambda may be considered as an instance of a struct implementing operator().
Note that stateless lambdas (lambdas that don't capture any variable) are implicitly convertible to function pointer. Here the implicit conversion doesn't work because of template substitution:
#include <iostream>
template <typename T>
void call_predicate(const T& v, void (*predicate)(T)) {
std::cout << "template" << std::endl;
predicate(v);
}
void call_predicate(const int& v, void (*predicate)(int)) {
std::cout << "overload" << std::endl;
predicate(v);
}
void foo(double v) {
std::cout << v << std::endl;
}
int main() {
// compiles and calls template function
call_predicate(42.0, foo);
// compiles and calls overload with implicit conversion
call_predicate(42, [](int v){std::cout << v << std::endl;});
// doesn't compile because template substitution fails
//call_predicate(42.0, [](double v){std::cout << v << std::endl;});
// compiles and calls template function through explicit instantiation
call_predicate<double>(42.0, [](double v){std::cout << v << std::endl;});
}
You should make your function binsearch more generic, something like:
template <typename T, typename Predicate>
T binsearch(const std::vector<T> &ts, Predicate p) {
// usage
for(auto& t : ts)
{
if(p(t)) return t;
}
// default value if p always returned false
return T{};
}
Take inspiration from standard algorithms library.
The lambda expression with empty capture list could be implicitly converted to a function pointer. But the function pointer predicate is taking T as its parameter, that need to be deduced. Type conversion won't be considered in template type deduction, T can't be deduced; just as the error message said, candidate template (i.e. binsearch) is ignored.
You can use operator+ to achieve this, it'll convert lambda to function pointer, which will be passed to binsearch later and then T will be successfully deduced[1].
binsearch(a, +[](int e) -> bool { return e >= 5; });
// ~
Of course you could use static_cast explicitly:
binsearch(a, static_cast<bool(*)(int)>([](int e) -> bool { return e >= 5; }));
Note if you change predicate's type to be independent of T, i.e. bool (*predicate)(int), passing lambda with empty capture list would work too; the lambda expression will be converted to function pointer implicitly.
Another solution is changing the parameter type from function pointer to std::function, which is more general for functors:
template <typename T> int binsearch(const std::vector<T> &ts, std::function<bool (typename std::vector<T>::value_type)> predicate) {
...
}
then
binsearch(a, [](int e) -> bool { return e >= 5; });
[1] A positive lambda: '+[]{}' - What sorcery is this?
Why is the compiler not convinced that my lambda has the right type?
Template functions being told to deduce their template parameters do no conversion. A lambda is not a function pointer, so there is no way to deduce the T in that argument. As all function arguments independently deduce their template parameters (unless deduction is blocked), this results in an error.
There are a number of fixes you can do.
You can fix the template function.
template <class T>
int binsearch(const std::vector<T> &ts, bool (*predicate)(T))
Replace the function pointer with a Predicate predicate or Predicate&& predicate and leave the body unchanged.
template <class T, class Predicate>
int binsearch(const std::vector<T> &ts, Predicate&& predicate)
Use deduction blocking:
template<class T>struct tag_t{using type=T;};
template<class T>using block_deduction=typename tag_t<T>::type;
template <class T>
int binsearch(const std::vector<T> &ts, block_deduction<bool (*)(T)> predicate)
optionally while replacing the function pointer with a std::function<bool(T)>.
You can fix it at the call site.
You can pass T manually binsearch<T>(vec, [](int x){return x<0;}).
You can decay the lambda to a function pointer with putting a + in front of it +[](int x) ... or a static_cast<bool(*)(int)>( ... ).
The best option is Predicate one. This is also what standard library code does.
We can also go a step further and make your code even more generic:
template <class Range, class Predicate>
auto binsearch(const Range &ts, Predicate&& predicate)
-> typename std::decay< decltype(*std::begin(ts)) >::type
The -> typename std::decay ... trailing return type part can be eliminated in C++14.
A benefit to this is that if the body also uses std::begin and std::end to find begin/end iterators, binsearch now supports deques, flat C-style arrays, std::arrays, std::strings, std::vectors, and even some custom types.
If you have any control over binsearch I suggest you refactor it:
template <typename T, typename Predicate>
int binsearch(std::vector<T> const& vec, Predicate&& pred) {
// This is just to illustrate how to call pred
for (auto const& el : vec) {
if (pred(el)) {
// Do something
}
}
return 0; // Or anything meaningful
}
Another way for you is to perform type-erasure on your functor objects/function pointers/whatever... by embedding them into an std::function<bool(T const&)>. To do so, just rewrite the function above as:
template <typename T>
int binsearch(std::vector<T> const& vec, std::function<bool(T const&)> pred);
But since template argument deduction does not do any conversion, you need to explicitly feed your function like the following:
auto my_predicate = [](int x) { return true; }; // Replace with actual predicate
std::vector<int> my_vector = {1, 2, 3, 4};
binsearch(my_vector, std::function<bool (int const&)>(my_predicate));
However given the description of your function, it seems it does the same job as std::find_if.
std::vector<int> my_vector = {1, 12, 15, 13, 16};
auto it = std::find_if(std::begin(my_vector), std::end(my_vector),
[](int vec_el) { return !vec_el%5; });
// it holds the first element in my_vector that is a multiple of 5.
if (it != std::end(my_vector)) {
std::cout << *it << std::endl; // prints 15 in this case
}
Note that to do a binary search, you need more than just a predicate: you need a predicate that defines an order on your range AND a target value.
A function pointer and a lambda function is not the same thing.
An object t can not be assigned to predicate where:
bool (*predicate)(int)
and
auto t = [](int e) -> bool { return e >= 5; });
Might as well use std::function<bool(int)>. Your signature will look like this:
template <typename T>
int binsearch(const std::vector<T> &ts, std::function<bool(T)> predicate){
// ...
}
Now that's not a function pointer, You'll need to bind your founction pointers if they are necessary, (I assume you're fine with just lambdas)

c++ functions as template arguments

I'm experiencing some problems which can be resumed by the following piece of code:
template <typename Key, typename Data, typename fct>
size_t wrapper(const std::pair<Key, Data> & p)
{
return fct(p.first);
}
int main(int argc, char *argv[])
{
size_t val =
wrapper<int, int, dft_hash_fct<int>>(std::pair<int,int>(5,9));
return 0;
}
I'm using clang compiler version 3.4 and this code does not compile with the following error
test-tmp.C:17:5: error: no matching function for call to 'wrapper'
wrapper<int, int, dft_hash_fct<int>>(std::pair<int,int>(5,9));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test-tmp.C:9:8: note: candidate template ignored: invalid explicitly-specified argument
for template parameter 'fct'
The idea is to wrap a hash function (the template parameter fct) on std::pair for only taking the first field.
dft_hash_fct is another template defines as follows:
template <typename Key>
size_t dft_hash_fct(const Key & key)
{
return SuperFastHash(key);
}
This generic function works; it has been used in other contexts.
The purpose of all this is to reuse a hash based set (not map) as a map of keys to items of any type. The hash based ser receives a hash function in construction time.
Thanks for your comments (David, Andrey and Kazark)
Edited:
Well, I see, typename fct is a type, so I cannot handle as a pointer function; sorry for the trivia. Unfortunately, I believe that the approach of passing the function as parameter in the wrapper does not work, because the hash set expects a function pointer with the following signature:
size_t (*the_function)(const Key & key);
So, realizing this, thanks to your observations, I changed the code in question to:
template <typename Key, typename Data, size_t (*fct)(const Key & k)>
size_t wrapper(const std::pair<Key, Data> & p)
{
return (*fct)(p.first);
}
int main(int argc, char *argv[])
{
size_t val =
wrapper<int, int, dft_hash_fct<int>>(std::pair<int,int>(5,9));
return 0;
}
that compiles, links and runs. In addition, I put this line:
size_t (*fct)(const std::pair<int, int>&) =
wrapper<int, int, dft_hash_fct<int>>;
cout << (*fct)(std::pair<int, int>(4,6)) << endl;
And that compiles, links ans runs too. So, I can say that the compiler (and of course according to the language) can instantiate the function and handle a function pointer to it.
So, after that I tried to modify my original code, which is a derived class of HAshSet intended for managing pairs hashed by first field.
I declare some as:
template <typename Key, typename Data>
class HashMap : public HashSet<std::pair<Key, Data>>
{
...
HashMap(size_t (*function)(const Key & key))
: HashSet<Key, Data>(wrapper<Key, Data, function>)
{
}
..
};
But the compilation (with std=c++11) fails with the error
./tpl_dynSetHash.H:353:7: error: no matching constructor for initialization of
'HashSet<std::pair<unsigned long, long>>'
: HashSet<std::pair<Key,Data>(
^
testDynSetHash.C:178:8: note: in instantiation of member function
'HashMap<unsigned long, long>::HashMap' requested here
HMap table;
However, if I substitute the call to base constructor by
: HashSet<Key, Data>(wrapper<Key, Data, dft_hash_fct<Key>)
That compiles fine. Thus, I believe that the problem is with the parameter type declaration (but I do not know what is).
The standard idiom to pass functions is to pass them as function objects, e.g.
template <typename Key, typename Data, typename Fct>
size_t wrapper(const std::pair<Key, Data> & p, Fct fct)
{
return fct(p.first);
}
Then call the wrapper using:
int main(int argc, char *argv[])
{
// no explicit template arguments required
size_t val =
wrapper(std::pair<int,int>(5,9), &dft_hash_fct<int>);
return 0;
}
In your code, on the other hand:
template <typename Key, typename Data, typename fct>
size_t wrapper(const std::pair<Key, Data> & p)
{
return fct(p.first);
}
typename fct introduces an alias for a type. Inside this function, fct names a type; therefore fct(p.first) creates an object of type fct, and this object needs to be converted to a size_t in order to return it from wrapper. You can use this as well, but the type you had to use would have to look like this:
struct dft_hash_fct_t
{
size_t result;
dft_hash_fct_t(int p) : result(SuperFashHash(p)) {}
operator size_t() const { return result; }
};
Which is probably not what you intended.
The template declaration in
template <typename Key, typename Data, typename fct>
size_t wrapper(const std::pair<Key, Data> & p)
{
return fct(p.first);
}
declares template parameterfct as a type, but you are trying to pass a function pointer to it. You can make fct function pointer template parameter like this:
template <typename Key, typename Data, size_t(*fct)(const Key&)>
size_t wrapper(const std::pair<Key, Data> & p)
{
return fct(p.first);
}
However, the more idiomatic way is (as DyP says) to pass a function object so that the function works with function pointers as well as objects overloading operator():
template <typename Key, typename Data, typename Fct>
size_t wrapper(const std::pair<Key, Data> & p, Fct fct)
{
return fct(p.first);
}
Then when calling it you pass the function as a parameter
wrapper(std::pair<int,int>(5,9), dft_hash_fct<int>);
The code you wrote makes no sense within the context of your intent. Your fct template parameter is a type. That means that
return fct(p.first);
is a function-style cast, not an application of () operator (i.e. it is not a function call). In your code you are attempting to cast p.first to type fct and then attempting to return the result of that cast as size_t. Was that your intent? I doubt that it was. On top of that you are trying to pass a function pointer value dft_hash_fct<int> as a template argument for fct, i.e. you are passing a value where a type is expected. How did you expect it to work?
The description you provided seems to imply that you actually wanted to call a functor with type fct from inside wrapper instead of performing a cast. In order to do that you have to obtain the functor itself somehow. Remember again that fct is not a functor, its is just the type of the functor.
The typical approach would be to pass the functor from the outside, as function parameter
template <typename Key, typename Data, typename fct>
size_t wrapper(const std::pair<Key, Data> & p, fct f)
{
return f(p.first);
}
Now you can use your wrapper template with class-based functors, as well as with ordinary functions
size_t val = wrapper(std::pair<int,int>(5,9), dft_hash_fct<int>);
Note that dft_hash_fct<int> has to be supplied as function argument, not as template argument.
There's no need to explicitly specify template arguments, since they will be deduced by the compiler.