avoid pointer-to-member-function for non-class type

  • A+

I am writing a kind of container class, for which I would like to offer an apply method which evaluates a function on the content of the container.

template<typename T> struct Foo {     T val;      /** apply a free function */     template<typename U> Foo<U> apply(U(*fun)(const T&))     {         return Foo<U>(fun(val));     }      /** apply a member function */     template<typename U> Foo<U> apply(U (T::*fun)() const)     {         return Foo<U>((val.*fun)());     } };  struct Bar{}; template class Foo<Bar>; // this compiles //template class Foo<int>; // this produces an error 

The last line yields error: creating pointer to member function of non-class type ‘const int’. Even though I only instantiated Foo and not used apply at all. So my question is: How can I effectively remove the second overload whenever T is a non-class type?

Note: I also tried having only one overload taking a std::function<U(const T&)>. This kinda works, because both function-pointers and member-function-pointers can be converted to std::function, but this approach effectively disables template deduction for U which makes user-code less readable.


Using std::invoke instead helps, it is much easier to implement and read

template<typename T> struct Foo {     T val;      template<typename U> auto apply(U&& fun)     {         return Foo<std::invoke_result_t<U, T>>{std::invoke(std::forward<U>(fun), val)};     } };  struct Bar{}; template class Foo<Bar>; template class Foo<int>; 

However, this won't compile if the functions are overloaded

int f(); double f(const Bar&); Foo<Bar>{}.apply(f);  // Doesn't compile 

The way around that is to use functors instead

Foo<Bar>{}.apply([](auto&& bar) -> decltype(auto) { return f(decltype(bar)(bar)); }); 

Which also makes it more consistent with member function calls

Foo<Bar>{}.apply([](auto&& bar) -> decltype(auto) { return decltype(bar)(bar).f(); }); 


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: