5

I do not understand why neither the lambda nor the function are recognized as an std::invocable compliant types in the following code:

#include <concepts>
#include <iostream>

void f( std::invocable auto callback)
{
    callback(47);
}

void function_callback(int i)
{
    std::cout << i << std::endl;
}

auto lambda_callback = [](int i )
{
    std::cout << i << std::endl;
};

int main(int) 
{
    f(&function_callback);
    f(lambda_callback);
}

I am using GCC trunk with -std=c++2a flag enabled.

nyarlathotep108
  • 5,275
  • 2
  • 26
  • 64
  • 1
    If you get build errors, always copy-paste them in full and complete and as text into the question itself. And add comments on the lines where you get the errors. – Some programmer dude Jun 08 '20 at 15:05

1 Answers1

15

If you look at the definition of invocable (or in the standard):

template< class F, class... Args >
concept invocable =
  requires(F&& f, Args&&... args) {
    std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
      /* not required to be equality preserving */
  };

What this means:

void f( std::invocable auto callback)

And it might be clearer if we write it long-form:

template <typename F>
    requires std::invocable<F>
void f(F callback);

Is that F is invocable with no arguments - that it's a nullary function (Args... is an empty pack here). Neither your function nor your lambda are nullary functions - they're both unary, so the constraint correctly rejects those.

What you probably want is:

void f( std::invocable<int> auto callback)

which checks if callback is invocable with a single argument of type int.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • I am not 100% sure I have understood the reason why `Args...` is considered a *no argument* instead of being deduced to `int` automatically, but your proposed fix works. – nyarlathotep108 Jun 08 '20 at 15:10
  • 7
    @nyarlathotep108 Concepts are _never_ deduced. Concepts are specified. – Barry Jun 08 '20 at 15:12
  • is there a way to really say "any" invocable type using concepts, without rolling back to template syntax? – nyarlathotep108 Jun 08 '20 at 15:26
  • 3
    @nyarlathotep108 What would you even do with that information? You have a template that's constrained on a type that's invocable _somehow_ - but you don't know how? In the general sense, it's not possible to even answer. – Barry Jun 08 '20 at 15:41
  • 2
    @nyarlathotep108: Remember: constraints are supposed to express how you intend to use a thing. You aren't going to call it with "any" arguments; you're going to call it with *some* arguments. So your constraint should express your intentions on your usage of the function. – Nicol Bolas Jun 08 '20 at 15:43