0

I want to create a templated function which accepts and invokes a callable object(except pointer to data members) with arguments to pass to it. I want the template to only accept the following types:-

  1. Pointers to functions
  2. Pointers to member functions
  3. Lambda
  4. bind expressions
  5. std::function
  6. Functors

Like this...

template< class Function, class... Args >
explicit X( Function&& f, Args&&... args );

But the first argument is accepting any type and I want to create some validation such that it only accept callable objects and throw error(preferably in compile-time) if it invalidates.

Tharani B
  • 21
  • 1
  • 1
    Have you looked at [std::is_invocable](https://en.cppreference.com/w/cpp/types/is_invocable) ? See the examples at the bottom of the page. – Richard Critten Jan 15 '23 at 09:45
  • @RichardCritten -- pointer-to-data-member is invocable. – Pete Becker Jan 19 '23 at 19:40
  • Copy/pasted from [dupe](https://stackoverflow.com/questions/74940437/restrict-function-template-for-member-functions-only). Just the opposite is asked which is trivial. – Jason Jan 21 '23 at 09:03
  • Reopened. The claimed duplicate asks about restricting a template to **member functions only**. This question is about allowing all callable types except pointer-to-member-data. – Pete Becker Jan 21 '23 at 15:05

1 Answers1

3

There's a C++20 concept just for this purpose:

template<class Function, class... Args>
    requires (std::invocable<Function, Args...>
        && !std::is_member_object_pointer_v<Function>)
void X(Function&& f, Args&&... args);

(Edited to add is_member_object_pointer_v due to comments below.)

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • I don't think this answers the question. I haven't paid attention recently, so some more recent standard may have stepped on the meaning of "callable object", but back when all this was first introduced, a pointer-to-data-member was a callable object, hence, invocable. The question asks how to exclude pointer-to-data-member. – Pete Becker Jan 15 '23 at 17:27
  • @PeteBecker: Please show an example of what you're talking about on http://godbolt.org or similar. – John Zwinck Jan 19 '23 at 08:44
  • We usually associate "call" with "function", so people naturally turn "callable type" into "something function-like". But it's actually broader than that. Here's the description from cppreference (emphasis added): "Class template std::function is a general-purpose polymorphic function wrapper. Instances of std::function can **store, copy, and invoke** any CopyConstructible Callable target -- functions (via pointers thereto), lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and **pointers to data members.**" – Pete Becker Jan 19 '23 at 15:02
  • So, after `struct X { int i; }; X x; std::function f(&X::i, x);`, calling `f()` returns the value of `x.i`. (caution: code written but not tested) – Pete Becker Jan 19 '23 at 15:02
  • @PeteBecker `std::function` is not valid. – John Zwinck Jan 19 '23 at 16:02
  • @PeteBecker: I eventually figured out what syntax you meant, but it turns out not to be relevant because you're talking as if someone could pass a pointer-to-data-member and it would magically become wrapped in an std::function before the constraint checks it. Of course that will not happen. If the caller explicitly wraps a pointer-to-data-member in an std::function before passing that function to `X()`, there is nothing we can do to detect it using C++ language features. If you have a better answer, please post it. – John Zwinck Jan 19 '23 at 19:23
  • Sigh. The point is that `std:invocable` is defined in terms of callable types; pointer-to-data-member is a callable type, as the question clearly acknowledges. `std::invocable` will report that a pointer-to-data-member is invocable; the question is how to avoid that. This answer is simply wrong. – Pete Becker Jan 19 '23 at 19:38
  • @PeteBecker: Finally I got your point. Here's what you were trying to explain: https://godbolt.org/z/e75vxfqrr - I've edited my answer to deal with this. – John Zwinck Jan 21 '23 at 08:58
  • Yeah, my bad; I only said that pointer-to-member-data is invocable three times; should have been clearer. – Pete Becker Jan 21 '23 at 15:06