简体   繁体   中英

Is it possible to make a function template take a `decltype` from a function reference?

I've always had difficulty understanding the std::function template. It seems to use magic that I don't know yet. It's template arguments are class R , class... ARGS . Yet it can be passed to the template as std::function<void> or std::function<void()> . An example with parameters: std::function<void, int, float> or std::function<void(int, float)> . Was this 2nd syntax introduced in c++11 ? I don't think this was valid prior.

Also, is there a way to get the decltype of a function and pass it to the function template? It would make setup of the function template so much easier.

Here is an example:

#include <functional>
using namespace std;

///////////////////////////////////////////////////////////////////////////////
// this works
void x() {}
void y(int p0) {}

int main1()
{
  using namespace std::placeholders;
  function<decltype(y)> functors[] = { bind(x), bind(y, _1) };
  functors[0](1);
  functors[1](1);
  return 0;
}

///////////////////////////////////////////////////////////////////////////////
// this doesn't work
struct X
{
    void x() {}
    void y(int p0) {}
    void z(int i, int p0)
    {
      using namespace std::placeholders;
      static function<decltype(&X::y)> functors[] = { bind(&X::x, _1), bind(&X::y, _1, _2) };
      functors[i](this, p0);
    }
};

int main2()
{
  X xobj;
  xobj.z(0, 1);
  xobj.z(1, 1);
  return 0;
}

int main()
{
    return main1() + main2();
}

std::function accepts one template argument, which must be a function type. You cannot use std::function<void, int, float> . std::function<void(int, float)> is the only valid syntax.

std::function was introduced in C++11. There's no std::function prior to that. There was std::tr1::function though, defined in TR1, which used the same std::function<void(int, float)> syntax.

The decltype thing you're looking for is probably something like:

template<typename T>
struct transform_to_free_function;

template <typename Target, typename R, typename... Args>
struct transform_to_free_function<R (Target::*)(Args...)>
{
    using type = R(Target*, Args...);
};

Note: 1) type is now a public member 2) it should rather be a function type, not a pointer for this purpose. It isn't straightforward to make a non-pointer type from a pointer type, but otherwise you had to use a std::remove_pointer on it.

The rest of your example then compiles fine:

#include <functional>
using namespace std;

template<typename T>
struct transform_to_free_function;

template <typename Target, typename R, typename... Args>
struct transform_to_free_function<R (Target::*)(Args...)>
{
    using type = R(Target*, Args...);
};

struct X
{
    void x() {}
    void y(int p0) {}
    void z(int i, int p0);
};

void X::z(int i, int p0)
{
    using namespace std::placeholders;
    static function<transform_to_free_function<decltype(&X::y)>::type>
    functors[] = { bind(&X::x, _1), bind(&X::y, _1, _2) };
    functors[i](this, p0);
}

int main()
{
    X xobj;
    xobj.z(0, 1);
    xobj.z(1, 1);
    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM