jeudi 31 décembre 2015

reflection woes utilizing generalized lambda with parameter from this pointer

I have 3 compilers disagreeing on the below C++14 code:

#include <type_traits>

template <typename P, typename F>
constexpr auto can_call(P* p, F&& f) -> decltype(f(p),std::true_type{}) { return {}; }

template <typename F>
constexpr std::false type can_call(void const*, F&&) { return {}; }

struct C {
  C() { auto pc = can_call(this, [&](auto p) -> decltype(p->f(3)) {}); }
  void f(int);
};

template <typename T>
struct CT {
  CT() { auto ptc = can_call(this, [&](auto p) -> decltype(p->f(3)) {}); }
  void f(T);
};

int main()
{
  C oc;
  auto pc = can_call(&oc, [&](auto p) -> decltype(p->f(3)) {});
  CT<int> oct;
  auto ptc = can_call(&oct, [&](auto p) -> decltype(p->f(3)) {});
}

clang++ 3.7 accepts it without a hitch.

g++ 4.9, 5.1, 5.2, 5.3 and trunk fail the CT<T> constructor, with the message:

t.cpp: In instantiation of ‘CT<T>::CT() [with T = int]’:
t.cpp:24:11:   required from here
t.cpp:16:61: error: base operand of ‘->’ has non-pointer type ‘auto:2’
     CT() { auto ptc = can_call(this, [&](auto p) -> decltype(p->f(3)) {}); }
                                                              ^

VisualStudio 2015 Community is the exact opposite of g++ and fails all lambdas, except the templated CT<T> constructor, complaining that left of '->f' must be a pointer. (I have not checked if perhaps it wrongly gets the std::false_type result in the CT<T> constructor.)

From this I have two questions:

  1. What is expected? I have tried to read the (draft C++17) standard from github, but to be honest I don't even know where to look, especially since the compilers disagrees a bit too much.
  2. Can the intended reflection be portably implemented in a different way? I want (not need) the functionality to improve compilation error messages from a library.




Aucun commentaire:

Enregistrer un commentaire