Recently I was trying to create flexible observer pattern implementation which hides boost::signal. I almost succeeded.
I have a Observer class which has to have an update method matching signature provided by template parameter.
Example of use:
Observable<void(float, float)> observable;
Observer<void(float, float)> observer;
observable.attach(&observer);
observable.notify(Observable::Arguments(10.0f, 1.0f)); // invokes observer->update(10.0f, 1.0f);
Everything works just fine if observer does not have overloaded update method. In that case boost::bind can not deduce correct method to use. Unfortunately I can't use explicit casting because I don't know update arguments (this information is in FunctionSignature).
Following method causes troubles:
class Observable <typename FunctionSignature>
{
...
template <class DerivedObserverClass>
void attach(DerivedObserverClass* observer)
{
STATIC_ASSERT((boost::is_base_of<ObserverType, DerivedObserverClass>::value));
ConnectionsMap::iterator it = connections.find(observer);
if (it == connections.end() || !it->second.connected()) {
// i would like to do something like
// boost::function<FunctionSignature> f;
// f = boost::bind(&static_cast<FunctionSignature>DerivedObserverClass::update, observer, _1);
// singnalSlot is defined as boost::signal<FunctionSignature>
// this works as long, as Derived class doesn't have overloaded update method
connections[observer] = signalSlot.connect(boost::bind(&DerivedClass::update, observer, _1));
} else {
throw std::invalid_argument("Observer already attached.");
}
}
I think that boost::function could help to solve this problem. I don't know how to bind it with correct member method using only template signature.
Is it even possible?
No, boost::function won't help you either. 13.4.3 says
Nonstatic member functions match targets of type
“pointer-to-member-function;” the function type of the pointer to
member is used to select the member function from the set of
overloaded member functions.
This means you cannot take an address of overloaded member function, pass it to any kind of function object (templated or not, boost or std or whatever), and hope the overloading will resolve itself. You need a genuine honest pointer-to-member-function type at the left-hand side of the assignment.
You will have to convert your FunctionSignature to a pointer-to-member-function type somehow. Here's some old-fashioned template magic that does what you need, for a limited number of function arguments. c++0x might have a better, more general solution.
template <typename C, typename F>
struct tomemfun;
template <typename C, typename res>
struct tomemfun<C, res()>
{
typedef res (C::*memfun_t)();
};
template <typename C, typename res, typename arg1>
struct tomemfun<C, res(arg1)>
{
typedef res (C::*memfun_t)(arg1);
};
template <typename C, typename res, typename arg1, typename arg2>
struct tomemfun<C, res(arg1, arg2)>
{
typedef res (C::*memfun_t)(arg1, arg2);
};
// repeat with more arguments as needed
Now you can use
tomemfun<DerivedClass, FunctionSignature>::memfun_t update = &DerivedClass::update;
and it will resolve to the right overloaded function.
boost might already have such a conversion template, but I couldn't find it.
Related
I'm writing a delegate library and stubled upon this problem: Let's say I have overloaded functions named foo like this:
int foo(double d);
double foo(int d);
How would I write my template argument list if I want to resolve which function is meant by specifying a signature as a template parameter. I basically want this syntax (yet it shall work with any signature):
Delegate d = make_delegate<&foo,int(double)>(); // "Delegate" is automatically deduced as Delegate<int(double)>
I managed to resolve it by using the following helper template, but it only works if I write the parameter types of the function signature manually. I struggle to forward the variadic parameter pack Args... (which is encoded in the Args_pack specialization) to the function signature.
template<typename... Args>
struct Args_pack {}
template<typename Signature>
struct Identify_signature_type;
template<typename Return, typename... Args>
struct Identify_signature_type<Return(Args...)> {
using T_return = Return;
using Args_pack = Args_pack<Args...>;
};
template<auto Signature> using Identify_signature = Identify_signature_type<decltype(Signature)>;
template<typename Signature, typename Identify_signature_type<Signature>::T_return Function(double /* important magic needed here */)>
auto make_delegate()
{...}
Delegate d = make_delegate<int(double), &foo>(); // Works. However, it would be nice if the template parameters could exchange places.
You can add a * to the signature to get the right function pointer type.
template<typename Signature, Signature* fptr>
auto make_delegate()
{...}
How do I create a metafunction that takes any kind of function pointer? In the code below, how do I get rid of "decltype(&f)" ?
template <class FuncType, FuncType functionPointer>
void runFunc()
{
functionPointer();
}
runFunc<decltype(&f),f>();
I don't want to have to specify the type of f seperately; the information is already there in f. I'd prefer not to resort to defines to solve this.
This is basically the templated function type idiom applied to meta-programming; I don't want to know the type of f, but whatever I get in apparently allows me to call operator() on it.
Stuff I've tried:
Different order for the template parameters; since later parameters seem to be guessable when you have a function; not possible because then you would need to forward declare FuncType, in order to have it as the type for functionPointer
Switching it around so that you specify returntype and parameters and give a function pointer of that type; cannot instantiate a template with variable template arguments in the middle; that looks like below:
template <class ReturnType, class ... ArgTypes, ReturnType (*functionPointer)(ArgTypes...)>
void runFunc()
{
functionPointer();
}
runFunc<void, int, f>(); // error; invalid template argument for 'ArgTypes', type expected
There's a bit more context here on github: https://github.com/TamaHobbit/FuncTest/blob/master/FuncTest/FuncTest.cpp
You can use this:
template <typename FuncType>
void runFunc(FuncType functionPointer )
{
functionPointer();
}
runFunc(f);
Right now there is unfortunately no good way of doing this.
The standard committee has, however, accepted a proposal that makes this valid code:
template <auto functionPointer>
void runFunc() {
functionPointer();
}
Compiler support should be coming soon.
Is it possible to get the return type of a template member function at compile time?
I guess I need something along the lines of:
template<class T>
struct SomeClass
{
// T must have a function foo(int), but do not know the
// return type, it could be anything
using RType = ??? T::foo(int) ???; // Is it possible to deduce it here?
}
What you want to do can be achieved by using the decltype operator together with the std::declval template.
decltype(EXPRESSION) yields – at compile time – the type that EXPRESSION would have. The EXPRESSION itself is never evaluated. This is much like sizeof(EXPRESSION) returns the size of whatever EXPRESSION evaluates to without ever actually evaluating it.
There is only one problem: Your foo is a non-static member function so writing decltype(T::foo(1)) is an error. We somehow need to obtain an instance of T. Even if we know nothing about its constructor, we can use std::declval to obtain a reference to an instance of it. This is a purely compile-time thing. std::declval is actually never defined (only declared) so don't attempt to evaluate it at run-time.
Here is how it would look together.
#include <type_traits>
template <typename SomeT>
struct Something
{
using RetT = decltype(std::declval<SomeT>().foo(1));
};
To see that it actually works, consider this example.
struct Bar
{
float
foo(int);
};
struct Baz
{
void
foo(int);
};
int
main()
{
static_assert(std::is_same<float, Something<Bar>::RetT>::value, "");
static_assert(std::is_same<void, Something<Baz>::RetT>::value, "");
}
While this does what I think you have asked for, it is not ideal in the sense that if you attempt to instantiate Something<T> with a T that doesn't have an appropriate foo member, you'll get a hard compiler error. It would be better to move the type computation into the template arguments such that you can benefit from the SFINAE rule.
template <typename SomeT,
typename RetT = decltype(std::declval<SomeT>().foo(1))>
struct Something
{
// Can use RetT here ...
};
If you know the argument types to your function call the following should work:
template<typename T>
struct X
{
typedef typename decltype(std::declval<T>.foo(std::declval<int>())) type;
};
If you don't you can still deduce the type of the function pointer and extract the return type:
template<class F>
struct return_type;
template<class C, class R, class... Args>
struct return_type<R(C::*)(Args...)>
{ using type = R; };
template<typename T>
struct X
{
typedef typename return_type<decltype(&T::foo)>::type type;
};
This will fail if T::foo is an overloaded function or member of T.
Unfortunately it is only possible to know the return type of some expression if you know with what arguments you are going to call it (which, unfortunately, often is a different place from where you need to know the return type)...
The std::function class is templated in such a way that when we want it to wrap a function like the following:
void printInt(int integer)
{
std::cout << int << '\n';
}
We use a std::function<void(int)>. Until recently I thought this was an odd nuance of the class, but a class I found while searching for delegate implementation in C++ uses a similar syntax.
What exactly is void(int), and what do we call it in technical terms? It seems to be the standard way of saying "a function that takes an int, and returns void" in codespeak, but my gut instinct says that's horribly oversimplified.
Secondly, I've noticed that when I see templates using this syntax they use variadic templates to allow multiple function signatures to be matched. From the link above:
template <typename T> class delegate;
template<class R, class ...A>
class delegate<R (A...)>
{
...
What is the reason for declaring the function as such instead of simply using the following:
template<class R, class ...A>
class delegate
{
...
The template parameter to std::function<Signature> is simply the type of a function, i.e., its signature. It uses the same notation as any function declaration except that it isn't named and the name is left out. You may have come across function pointers which use the same notation but the function signature is used for a pointer.
The reason std::function<Signature> (and apparently delegate<Signature>) are implemented using template specialization is to yield a nicer type:
template <typename T> class function;
template <typename R, typename... Args>
class function {
public:
R operator()(Args...);
// ...
};
template <typename R, typename... Args>
class other {
public:
R operator()(Args...);
// ...
};
int main() {
function<int(double, char)> f;
other<int, double, char> o;
}
Since the primary template for function<T> takes one type as argument, using the specialization the argument can be a normal function type. On the other hand, the same isn't done for other<T...> which, thus, gets a list of types.
It is worth nothing that std::function<T> objects can be passed around quite easily without any need to deal with many template arguments: since the function's signature is just a type, this class template takes just one template argument.
I want to be able to templatize a class on a member function without needing to repeat the arguments of the member function -- i e, derive them automatically.
I know how to do this if I name the class based on how many arguments the function takes, but I want to derive that as well.
Something like this, although this doesn't work (at least in MSVC 2008 sp1, which is my target compiler):
class Foo {
void func0();
int func2(char *, float);
};
template<typename T> class Wrapper;
// specialize for zero-argument void func
template<typename Host, void (Host::*Func)()> class Wrapper<Func> : public Base {
... specialization goes here ...
};
// specialize for two-argument value func
template<typename Host, typename Ret, typename Arg0, typename Arg1, Ret (Host::*Func)(Arg0, Arg1)> class Wrapper<Func> : public Base {
... specialization goes here ...
};
Through "Base" I can then treat these polymorphically. In the end, I want to use this to create a simple wrapper syntax for a scripting language:
WrapClass<Bar> wrap(
MemberFunction<&Bar::func0>("func0") +
MemberFunction<&Bar::func2>("func2")
);
However, that doesn't work: the specialization syntax is wrong, because you can't match a function pointer to a typename argument.
I believe you'll need to take a traits approach, the most common library of which is boost's, but if you wanted to avoid boost, it wouldn't be extremely difficult to roll your own if you limited the scope of the implementation to just pointer-to-member-functions and the traits on those you need (modern c++ design is a great book explaining the theory). Here's how I would do it with boost's function_traits and enable_if.
You could use a generic template argument, enable_if it for function pointers, then use function types (or type traits) to pull out out the information you need:
#include <boost/function_types/function_arity.hpp>
#include <boost/function_types/is_member_pointer.hpp>
template<typename T, class Enable = void> class Wrapper;
/* other specializations... */
// For member functions:
template <class T>
class Wrapper<T, typename enable_if<is_member_pointer<T> >::type>
{ /* function_arity<T>::value has the number of arguments */ };
See this and this
The C++ standard library provides mem_fun_ref which sort of works how you want, though it only works for nullary and unary functions. Of course, you can use a struct with all the parameters as your one argument.