Determine signatures of overloaded member functions - c++

Given some_type with a member function f it is possible to determine f's signature like this (and say let us place it in a tuple):
template <typename R, typename T, typename... A>
std::tuple<R, A...> signature_of_impl(R (T::*)(A...));
template <typename T>
using signature_of_member_f = decltype(signature_of_impl(&T::f));
struct some_type
{
int f(char, float);
};
using some_type_f_signature = signture_of_member_f<some_type>;
This obviously fails badly if f is overloaded. Is it possible to determine signatures of all existing overloads of f within some_type?

You can "ask" the compiler for the type of a specific function.
But there's no reflection in C++, you can't query what functions or even overloads of the same function exist in a class.

Related

How do I resolve an overloaded function by it's signature as a template parameter?

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()
{...}

SFINAE with functions and emulating partial template specialization

I am trying to make a function X that specializes when a member function Y is provided and if the member function Y is not provided the function X uses the global non member function Y to achieve the same effect.
I am currently trying to achieve this with the following code
template <typename Container, typename std::enable_if_t<std::is_same<
decltype(std::declval<Container>().y()),
decltype(std::declval<Container>().y())>::value>* = nullptr>
void do_something(Container&& container) {
return std::forward<Container>().y();
}
template <typename Container, typename std::enable_if_t<!std::is_same<
decltype(std::declval<Container>().y()),
decltype(std::declval<Container>().y())>::value>* = nullptr>
void do_something(Container&& container) {
return y(std::forward<Container>(container);
}
But in the case when the container has both a member function y and the global non member function y also works on it. There is a compile error because for the second version of the function the template argument is ill formed because a member function y is needed.
Any idea how I can go about resolving this issue?
NOTE: This is different from just detecting whether a class has a function of a given signature. Sorry if the question seems to ask that! The accepted answer below should make my intention clearer.
The typical approach is to dispatch to a pair of functions where one is preferred if your condition is met and the other is simply a fallback. The nice thing is you don't even need enable_if, just the trailing decltype:
template <class C>
auto do_something_impl(C&& c, int)
-> decltype(std::forward<C>(c).y())
{
return std::forward<C>(c).y();
}
template <class C>
auto do_something_impl(C&& c, ...)
-> decltype(y(std::forward<C>(c))
{
return y(std::forward<C>(c));
}
And now just pass in 0:
template <class C>
auto do_something(C&& c)
-> decltype(do_something_impl(std::forward<C>(c), 0))
{
return do_something_impl(std::forward<C>(c), 0);
}
The conversion sequence to int is better than the one to ..., so if the type has the member function you want, that overload will be preferred even if both are viable candidates.

C++ constraint on callable types as template parameters

I'm trying to port the following Scala code to C++:
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
I've tried something like:
template<template <typename> class F>
struct Functor {
template <typename A, typename B>
static F<B> map(const F<A> &fa, ??? f); // What's the type of `f`?
};
But I don't know how to express the type of f (which in Scala is A => B, or Function1[A, B]). Using std::function makes the compiler unable to do useful type inference, and also makes using lambdas awkward (I need to explicitly specify the template parameter, like
Functor<List>::map<Foo, Bar>(foos, [](const Foo &foo) -> Bar { return foo.toBar(); });
, otherwise the compiler just can't seem to infer what B is). A workaround seems to be:
template<template <typename> class F>
struct Functor {
template <typename A, typename A2B>
static auto map(const F<A> &fa, A2B f) -> F<decltype(f(fa[0]))>;
};
But this looks ugly, and F<A> might not always support the brackets operator (or ::value_type, for that matter). Is there any better way to implement this?
With std::result_of_t and generic lambdas you'll have nice enough calling code:
template<template <typename> class F>
struct Functor {
template <typename A, typename A2B>
static auto map(const F<A> &fa, A2B f) -> F<std::result_of_t<A2B(A)>>;
};
auto bars = Functor<std::vector>::map(foos, [](const auto& foo) { return foo.toBar(); });
Note however, that most of standard C++ containers have more than one template parameter. The easiest way so to make this code work with them you'll have to change definition of Functor to
template<template <typename...> class F>
struct Functor {
And you won't be able to specify other template parameters, e.g Allocator for the resulting container type, unless you provide a dedicated specialization for particular container.
The C++ way to do this is to define a function. Call it fmap.
Then clients who want to support it override fmap as a free function, where argument 1 takes a client object, and argument 2 takes a function that maps from the interior type to some other type.
You can write a trait that expresses "supports fmap" and does the "proper" type conversion, but it is annoying and not worth it. 'Supports fmap' is easier, and as useful.
Similarly for fbind etc.

Function signatures in C++ templates

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.

How to create boost::function from template signature

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.