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.
Related
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;
}
I try to pass to a variadic template function a list of references and pass it to another function. The code that I wrote is the following:
template <typename T>
void fun(cv::Point_<T> & pt) { pt.x++; pt.y++; }
template <class ... args>
void caller(args & ... list) {
typedef typename std::tuple_element<0, std::tuple<args...> >::type T;
std::array<std::reference_wrapper<T>, sizeof...(list)> values {list ... };
for(int i=0; i<values.size(); i++)
fun(values[i]);
}
then I call the function caller in this way:
cv::Point2f a, b, c;
caller(a, b, c);
the compiler give me the following error:
No matching function for call to 'fun'
Candidate template ignored: could not match 'Point_' against 'reference_wrapper'
what I missing?
Although std::reference_wrapper<T> has an implicit conversion to T&, you cannot use both an implicit conversion and template argument deduction at the same time, and template argument deduction is necessary to call fun.
Try
fun(values[i].get());
Even simpler is
template <typename...Args>
void caller(Args&...args)
{
auto tmp = { (func(args),0)..., 0 };
}
This uses the fact that parameter pack expansion can occur in braced init lists. Since func() returns void, we cannot simply use { func(args)... }, but use (func(args),0) to have an int. Finally, the last 0 is to ensure that the code compiles (and does nothing) in case of an empty parameter pack.
You can generalise this and write a template that calls a given generic function for every element of a pack:
template <typename Func, typename...Args>
void call_for_each(Func &&func, Args&&...args)
{
auto unused = { (func(std::forward<Args>(args)),0)...,0 };
}
which may be used like this (C++14)
int main()
{
int a=1;
double b=2.4;
auto func = [](auto&x) { std::cout<<' '<<x++; };
call_for_each(func,a,b);
std::cout<<'\n';
call_for_each(func,a,b);
std::cout<<'\n';
}
This uses a C++14 lambda (taking an auto argument). Note that the parameter pack must come last among the template parameters of call_for_each.
Since the goal of this might be to iterate over all args, here's a more generic solution. We are going to implement for_pack:
template<typename... Args, typename F>
void for_pack(F function, Args&&... args) {
using expand = int[];
(void)expand{(function(std::forward<Args>(args)), void(), 0)..., 0};
}
This will execute function for every args in Args.
Now, your function caller is much more trivial to implement:
template <typename... args>
void caller(args&... list) {
for_pack([&](cv::Point_<T>& arg){
fun(arg);
}, list...);
}
Since a google search for "c++ pass reference parameters to variadic template" gives this as first result, I'll put this generic solution here.
struct HH { /*...*/ void change_me() { /*...*/ } };
template<typename...T> void parms_r_refs() {}
template<typename H, typename...T> void parms_r_refs(H &h, T&...t) { h.change_me(); parms_r_refs(t...); }
template<typename...T> void parms_r_refs(T&...t) { parms_r_refs(t...); }
HH a, b, c;
..
parms_r_refs(a, b, c);
..
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.
I would like to create template class which could store function pointer and arguments for a this function so the function can be later invoked with this arguments.
I would like to write this universally and not to depend on argument types or number.
Here is a scatch of the idea with the use of variadic templates of c++11:
template<class T, typename... Params>
class LazyEvaluation {
private:
// Function to be invoked later
T (*f)(Params...);
// Params for function f
Params... storedParams; // This line is not compilable!
bool evaluated;
T result;
public:
// Constructor remembers function pointer and parameters
LazyEvaluation(T (*f)(Params...),Params... params)
: f(f),
storedParams(params) //this line also cannot be compiled
{}
// Method which can be called later to evaluate stored function with stored arguments
operator T&() {
// if not evaluated then evaluate
if (! evaluated) {
result = f(storedParams...);
evaluated = true;
}
return result;
}
}
I would like to have at least the public interface of this class type safe if it is possible. Although getting this work at least somehow is more important.
I've managed to save the variable number of arguments somehow. But I wasn't able to pass them to the function f. I will write it to answers, but I would like you to think about your own solutions before you see my ugly not working attempt.
I am tring to compile the code above with Microsoft Visual C++ Compiler Nov 2012 CTP (v120_CTP_Nov2012), but it would be best if a compiler independent solution would exist.
Thank you
Here is how I tried to solve it:
The parametr pack can be recursivle expanded and each parametr saved. Function store is supposed to do it. It uses one (two times overloaded) helper function.
template<typename T>
void storeHelperFunction(void*& memory, T last) {
*((T*)memory) = last;
memory = (void*)((char*)memory + sizeof(T));
}
template<typename T, typename... Params>
void storeHelperFunction(void*& memory, T first, Params... rest) {
storeHelperFunction(memory, first);
storeHelperFunction(memory, rest...);
}
template<typename... Params>
void store(void* memory, Params... args) {
// Copy of pointer to memory was done when passing it to this function
storeHelperFunction(memory, args...);
}
Function store takes a pointer to memory where the varialbe number of arguments is supposed to be saved.
The pointer can point to some dynamicly allocated memory or beter to the structure which size is equal to sizeof...(Params).
Such structure which has exactly any desiared size can be constructed using template metaprogramming:
template <int N>
struct allocatorStruct {
char byte1;
allocatorStruct<N-1> next;
};
template <>
struct allocatorStruct<1> {};
I am not sure what the standart says or how the other compilers than the microsoft one compile it. But using my compiler the sizeof(allocatorStruct) is equal to N for any N which is greater or equal to 1.
Hence allocatorStruct<sizeof...(Params)> has the same size as Params.
Another way to create something which has the same size as Params is to use a type char [sizeof...(Params)]. This has the disadvantage that the compiler passes only pointer to this array when you try to pass such array as argument.
That is why it is better to use allocatorStruct<sizeof...(Params)>.
And now the main idea:
When saving the function we can cast it to: T (*)(allocatorStruct<sizeof...(Params)>).
When saving the arguments for the function we can save them to struct of the type allocatorStruct<sizeof...(Params)>.
The size of the arguments is the same. Although the function pointer lies about the type of the function the function pointed to will get its data correctly.
At least I hoped. Depending on the calling convention I expected that the passed arguments can be reordered or wrong because of the difference between left to right saving arguments and right to left passing. But it wasn't the case. Using __cdecl calling convention only first argument was passed and the other was lost. With other calling conventions the program stoped working.
I didn't spend much time debugging it and looking to data in memory(on stack). Is it at least right way to go?
Simply use a lambda expression
// Some function.
int add(int a, int b) {
return a + b;
}
auto lazyFunc = [] { return add(1, 2); };
std::cout << lazyFunc() << std::endl; // Evaluate function and output result.
If you really want to create a class that only evaluates the function once (lazily), using variadic templates, you could do something like in the following code.
I also made the class as such that you don't have to create a new instance every time the parameters change. I use a std::tuple to store the given arguments, and compare against previously given arguments. If the arguments differ, then the function will be reevaluated.
Functions are passed around and stored using a std::function wrapper so I don't have to work with raw function pointers (yuck).
#include <iostream>
#include <functional>
#include <utility>
#include <tuple>
template <typename T>
class LazyEvaluation {};
template <typename ReturnType, typename... Params>
class LazyEvaluation<ReturnType(Params...)> {
private:
std::function<ReturnType(Params...)> func_;
ReturnType result;
std::tuple<Params...> oldParams; // Contains the previous arguments.
public:
explicit LazyEvaluation(std::function<ReturnType(Params...)> func)
: func_(std::move(func)) {}
template <typename... Args>
ReturnType operator() (Args&&... args) {
auto newParams = std::make_tuple(std::forward<Args>(args)...);
// Check if new arguments.
if (newParams != oldParams) {
result = func_(std::forward<Args>(args)...);
oldParams = newParams;
std::cout << "Function evaluated" << std::endl;
}
std::cout << "Returned result" << std::endl;
return result;
}
};
int main() {
auto f = [] (int a, int b) {
return a + b;
};
// Specify function type as template parameter.
// E.g. ReturnType(Param1Type, Param2Type, ..., ParamNType)
LazyEvaluation<int(int, int)> ld(f);
std::cout << ld(1, 2) << std::endl;
std::cout << ld(1, 2) << std::endl;
std::cout << ld(3, 4) << std::endl;
}
Output:
Function evaluated
Returned result
3
Returned result
3
Function evaluated
Returned result
7
Given the standard machinery for forming variadic index packs:
template <std::size_t... I> struct index_sequence {};
template <std::size_t N, std::size_t... I>
struct make_index_sequence : public make_index_sequence<N-1, N-1, I...> {};
template <std::size_t... I>
struct make_index_sequence<0, I...> : public index_sequence<I...> {};
and to call functions with unpacked tuple arguments:
template <typename Function, typename... Types, std::size_t... I>
auto apply_(Function&& f, const std::tuple<Types...>& t, index_sequence<I...>)
-> decltype(std::forward<Function>(f)(std::get<I>(t)...)) {
return std::forward<Function>(f)(std::get<I>(t)...);
}
template <typename Function, typename... Types>
auto apply(Function&& f, const std::tuple<Types...>& t)
-> decltype(apply_(f, t, make_index_sequence<sizeof...(Types)>())) {
return apply_(f, t, make_index_sequence<sizeof...(Types)>());
}
This is fairly straightforward:
template<typename Function, typename... Params>
class LazyEvaluation {
private:
typedef decltype(std::declval<Function>()(std::declval<Params>()...)) result_type;
// Function to be invoked later
Function f;
// Params for function f
std::tuple<Params...> storedParams;
mutable bool evaluated;
union {
std::aligned_storage<sizeof(result_type)> space;
mutable result_type result;
};
// Method which can be called later to evaluate stored function with stored arguments
void evaluate() const {
// if not evaluated then evaluate
if (! evaluated) {
new (&result) result_type{apply(f, storedParams)};
evaluated = true;
}
}
public:
// Constructor remembers function pointer and parameters
LazyEvaluation(Function f, Params... params)
: f(std::move(f)),
storedParams(std::move(params)...),
evaluated(false)
{}
~LazyEvaluation() {
if (evaluated)
result.~result_type();
}
operator result_type&() {
evaluate();
return result;
}
operator const result_type& () const {
evaluate();
return result;
}
};
template <typename Function, typename... Params>
LazyEvaluation<Function, Params...>
make_lazy(Function&& f, Params&&... params) {
return {std::forward<Function>(f), std::forward<Params>(params)...};
}
I've used a union and placement new to store the result of evaluation so that it doesn't need to be a default-constructible type, and some mutable tricks so that a const LazyEvaluator can be converted as well as a non-const instance.
I am trying to build a statically bound delegate class, where the member function is bound at compile time, thereby aiding optimisation.
I have the following code which works exactly how I want it to:
#include <iostream>
namespace thr {
template<typename T, T func>
struct delegate;
template<typename R,
typename C,
typename... A,
R (C::* mem_fun)(A...)>
struct delegate<R(C::*)(A...), mem_fun>
{
delegate(C* obj_)
: _obj(obj_)
{}
R operator()(A... a)
{
return (_obj->*mem_fun)(a...);
}
private:
C* _obj;
};
} // namespace thr
struct foo
{
double bar(int i, int j)
{
return (double)i / (double)j;
}
};
int main()
{
foo f;
typedef thr::delegate<decltype(&foo::bar), &foo::bar> cb;
cb c(&f);
std::cout << c(4, 3);
return 0;
}
However, the usage is not very elegant:
thr::delegate<decltype(&foo::bar), &foo::bar>
I would like to use a function template which deduces the template parameters and returns a delegate instance; something along the lines of (this code does not compile):
template<typename C, typename T, T func>
thr::delegate<T, func> bind(T func, C* obj)
{
return thr::delegate<decltype(func), func>(obj);
}
This would allow for more elegant syntax:
auto cb = bind(&foo::bar, &f);
Is it possible to deduce a non-type parameter in a function template?
Is what I'm trying to achieve even possible?
Would std::function help? http://www2.research.att.com/~bs/C++0xFAQ.html#std-function Your example looks quite close.
I think the compiler supplied STL does pretty horrible things to make it work smoothly. You may want to have a look at as an example before giving up.
Edit: I went out and tried what you try to accomplish. My conclusion is a compile error:
The return type of the bind (delegate) must name the pointer to member because it is your own requirement.
bind should accept the name of the pointer to member to be elegant (i.e. your requirement)
Compiler requires you to not shadow the template parameter with a function parameter or use the name in both parameters and return type.
Therefore one of your requirements must go.
Edit 2: I took the liberty of changing your delegate so bind works as you wish. bind might not be your priority though.
#include <iostream>
namespace thr {
template<typename C,typename R,typename... A>
struct delegate
{
private:
C* _obj;
R(C::*_f)(A...);
public:
delegate(C* obj_,R(C::*f)(A...))
: _obj(obj_),_f(f)
{}
R operator()(A... a)
{
return (_obj->*_f)(a...);
}
};
} // namespace thr
template<class C,typename R,typename... A> thr::delegate<C,R,A...> bind(R(C::*f)(A...),C* obj){
return thr::delegate<C,R,A...>(obj,f);
}
struct foo
{
double bar(int i, int j)
{
return (double)i / (double)j;
}
};
int main()
{
foo f;
auto c = bind(&foo::bar, &f);
std::cout << c(4, 6);
return 0;
}
It is possible to deduce other entities than types in a function signature, but function parameters themselves cannot then be used as template parameters.
Given:
template <size_t I> struct Integral { static size_t const value = I; };
You can have:
template <size_t N>
Integral<N> foo(char const (&)[N]);
But you cannot have:
Integral<N> bar(size_t N);
In the former case, N as the size of the array is part of the type of the argument, in the latter case, N is the argument itself. It can be noticed that in the former case, N appeared in the template parameters list of the type signature.
Therefore, if indeed what you want is possible, the member pointer value would have to appear as part of the template parameter list of the function signature.
There may be a saving grace using constexpr, which can turn a regular value into a constant fit for template parameters:
constexpr size_t fib(size_t N) { return N <= 1 ? 1 : fib(N-1) + fib(N-2); }
Integral<fib(4)> works;
But I am not savvy enough to go down that road...
I do however have a simple question: why do you think this will speed things up ? Compilers are very good at constant propagation and inlining, to the point of being able to inline calls to virtual functions when they can assess the dynamic type of variables at compilation. Are you sure it's worth sweating over this ?