Reputation: 9369
Consider the following program. I use h()
as an helper to resolve ambiguities with pointers to overloaded functions from cmath:
#include <cmath>
typedef double(*PF1)(double);
typedef double(*PF2)(double, double);
typedef double(*PF3)(double, double, double);
// etc...
auto h(PF1 p) -> decltype(p) {return p;}
auto h(PF2 p) -> decltype(p) {return p;}
auto h(PF3 p) -> decltype(p) {return p;}
int f(int) {return 0;}; // my math function
int main() {
//auto s_ = std::sin; // won't work as std::sin is overloaded
auto s = h(std::sin); // works, type of s is a double(*)(double)
auto p = h(std::pow); // OK.
// auto my_aim = h(f); // my aim is to make h() work with f too
}
Is there a smarter or more generic helper to deduct the type of a pointer to (a possibily) overloaded function given a pointer to the function itself, so that the deduction would "prefer" either the overload with only double types involved (as return type and arguments) if available, or one of other overloads otherwise.
Upvotes: 4
Views: 225
Reputation: 218088
The following may help:
constexpr auto h(double(*p)(double)) -> decltype(p) {return p;}
constexpr auto h(double(*p)(double, double)) -> decltype(p) {return p;}
constexpr auto h(double(*p)(double, double, double)) -> decltype(p) {return p;}
template <typename Return, typename ... Args>
constexpr auto h(Return (*p)(Args...)) -> decltype(p) {return p;}
int f(int) {return 0;}; // my math function
int main(int argc, char *argv[])
{
//auto s_ = std::sin; // won't work as std::sin is overloaded
auto s = h(std::sin); // works, type of s is a double(*)(double)
auto p = h(std::pow); // OK.
auto my_aim = h(f); // works too
return 0;
}
As long as h
arguments is in one provided (double(*p)(double..)
) or there is no overload (as for f
) (so template can deduce its type).
EDIT
Add a more generic class to handle that:
template<typename Sign, typename ... Signs>
struct identity : identity<Signs...>
{
using identity<Signs...>::h;
static constexpr auto h(Sign p) -> decltype(p) {return p;}
};
template<typename Sign>
struct identity<Sign>
{
static constexpr auto h(Sign p) -> decltype(p) {return p;}
template <typename T>
static constexpr auto h(T p) -> decltype(p) {return p;}
};
Let's use it with your example:
typedef identity<double(*)(double),
double(*)(double, double),
double(*)(double, double, double)> MyIdentity;
int f(int) {return 0;}; // my math function
int main(int argc, char *argv[])
{
auto s = MyIdentity::h(std::sin); // works : double(*)(double)
auto p = MyIdentity::h(pow); // works : double(*)(double, double)
auto my_aim = MyIdentity::h(f); // works : (int)(*)(int)
return 0;
}
Upvotes: 3
Reputation: 14184
The Boost libraries have the Boost.Functional/OverloadedFunction library, which is dessigned to wrap different overloads into a single function object:
boost::overloaded_function<
const std::string& (const std::string&)
, int (int)
, double (double)
> identity(identity_s, identity_i, identity_d);
// All calls via single `identity` function.
BOOST_TEST(identity("abc") == "abc");
BOOST_TEST(identity(123) == 123);
BOOST_TEST(identity(1.23) == 1.23);
I think your problem could be solved easily with this library. Even if this solution does not answer your question directly, I think using boost::overloaded_function
is a better way to bind different functions into one object and calling that different functions through one object only, which is your final goal, isn't? (I have deduced that following your previous question).
Upvotes: 0
Reputation: 37914
This is the closest thing I can get to what you are trying to do:
#include <cmath>
#include <functional>
template<typename R, typename ...A>
auto h(R f(A...)) -> std::function<R(A...)>
{
return std::function<R(A...)>(f);
}
int main() {
auto s = h<double, double>(std::sin);
auto p = h<double, double, double>(std::pow);
}
You still have to specify the return type and parameters of the function you are passing in, but that is because it would be ambiguous without specifying an overload.
if you had a function whose deduced parameters would be unambiguous, it would simply be:
int only_one_overload(int a, int b) {
return a + b;
}
auto x = h(only_one_overload);
I would recomend just using function pointers though:
double (*s)(double) = std::sin;
double (*p)(double, double) = std::pow;
Upvotes: 0