SFINAE指向重载函数的指针

时间:2014-01-12 12:17:31

标签: c++ c++11

考虑以下计划。我使用h()作为帮助来解决带有指向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
}

在给定指向函数本身的指针的情况下,是否有更智能或更通用的帮助器来减去指向(可能的)重载函数的指针的类型,因此推导将“更喜欢”仅包含双重类型的重载(如果可用,则返回类型和参数;否则返回其他重载之一。

3 个答案:

答案 0 :(得分:3)

以下内容可能有所帮助:

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;
}

只要提供hdouble(*p)(double..)个参数(或f)或没有重载(对于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;} }; )(因此模板可以推断其类型)。

修改

添加一个更通用的类来处理:

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;
}

让我们在你的例子中使用它:

{{1}}

答案 1 :(得分:0)

这是我最接近你想要做的事情:

#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);
}

您仍然需要指定要传入的函数的返回类型和参数,但这是因为如果不指定重载,它将是不明确的。

如果你有一个推导出的参数明确无误的函数,那就是:

int only_one_overload(int a,  int b) {
    return a + b;
}
auto x = h(only_one_overload);

我建议只使用函数指针:

double (*s)(double) = std::sin;
double (*p)(double, double) = std::pow;

答案 2 :(得分:0)

Boost库有Boost.Functional/OverloadedFunction库,它被分配以将不同的重载包装到单个函数对象中:

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);

我认为使用此库可以轻松解决您的问题。即使这个解决方案没有直接回答你的问题,我认为使用boost::overloaded_function是一种更好的方法将不同的函数绑定到一个对象中,只通过一个对象调用不同的函数,这是你的最终目标,不是吗? (我已按照您之前提出的问题推断出)