0

Using the insight of this question (and a few others) I have been able to write the following for interrogating normal lambda function type infromation (i.e. return type, argument count etc)

// helper classes ========================================
template <typename R, typename... A>
class lambda_traits_evaluation {
public:
  typedef R r_type;
  enum { n_args = sizeof...(A) };
  // ...
};

template <typename R, typename... A>
class lambda_traits_helper
  : public lambda_traits_evaluation<R,A...>{};

template <typename R, typename F, typename... A>
class lambda_traits_helper<R (F::*)(A...) const>
  : public lambda_traits_evaluation<R,A...>{};

// use class      ========================================
template <typename F>
class lambda_traits {
  typedef typename lambda_traits_helper<decltype(&F::operator())> helper_impl;
  // ...
}

I can then use this with lambda_traits<decltype(myLambda)> but that is where my smug coding ends because if my lambda is amp restricted for the gpu i.e.

auto myLambda = [](int) restrict(amp) -> void {};

as obviously the template specialisation is not picked up. However adding the new specialisation

template <typename R, typename F, typename... A>
class lambda_traits_helper<R (F::*)(A...) const restrict(amp)>
  : public lambda_traits_evaluation<R,A...> {};

still does not solve the problem as I discover that the compiler barks

error C3939: 'abstract declarator' : pointer to member functions, function
             pointers, references to functions with 'amp' restriction
             specifier are not allowed

is there another way to interrogate the types in lambdas or else a way to strip the restrict off the lambda type?

Community
  • 1
  • 1
geoff3jones
  • 605
  • 1
  • 7
  • 17

1 Answers1

2

The inability to form a pointer to an amp-restricted function, even in unevaluated context, is a bummer. There is however a workaround, which is viable as long as you can require the amp-restricted lambdas to be cpu,amp-restricted. In such case you can cast-away the amp-restriction, forming a pointer to the cpu-restricted member function -- which you can interrogate further.

See the following proof-of-concept:

#include <type_traits>

template <typename R, typename F, typename... A>
auto get_R(R (F::*)(A...) const) -> R
{}

template <typename L>
struct lambda_traits
{
    using ret_type = decltype(get_R(&L::operator()));
};

int main()
{
    auto lambda_1 = [](int) restrict(cpu,amp) -> void {};
    auto lambda_2 = [](int) restrict(cpu,amp) -> int { return 0; };

    // Test:
    static_assert(std::is_same<lambda_traits<decltype(lambda_1)>::ret_type, void>::value, "Failed 1.");
    static_assert(std::is_same<lambda_traits<decltype(lambda_2)>::ret_type, int>::value, "Failed 2.");
}

Hope that helps!

  • Mmm neat, this is indeed a viable work around. I was worried that I would not be able to use this to specialise templated `restrict(amp)` functions as I was expecting this to have thrown away the `restrict(cpu)` part. Bizarrely the cpu restriction seems to cling to the lambda definition (although it is not callable) even inside an enclosing `amp` restricted scope. I'm not sure if this a bug with the implementation or what but it feel a bit broken... Either way thanks for spotting it, and I can't think of any major downsides off hand as to requiring the extra `cpu` restriction on a lambda. – geoff3jones Jan 22 '14 at 15:51
  • Yes, restrictions are not (informally) "dropped when crossing a restriction boundary". Otherwise you would not be able to call the parallel_for_each with an amp-restricted lambda from a cpu-restricted context. – Lukasz Mendakiewicz Jan 22 '14 at 21:20
  • Ah of course that is a good point, I think I was getting confused by drawing parallels with member function overloading on `restric`. Cheers for the help and ideas! – geoff3jones Jan 23 '14 at 16:12