I've worked hard this morning to understand concepts a bit more (still a newbie), and I've stumbled to something strange.
I wanted to understand how good concepts work with Lambda functions, I've tried toying around with them a lot.
Lets start with this code (that works!):
#include <concepts>
#include <stdio.h>
template <typename T>
concept Integral =
requires(T n)
{
{ n } -> std::convertible_to<int>;
};
template <typename Operation>
concept CalculatorOperation =
requires(Operation&& op, int a, int b)
{
{ op(a, b) } -> Integral;
};
template <CalculatorOperation Operation>
static inline constexpr Integral auto Calculator(const Integral auto First,
const Integral auto Second)
{
return Operation{}(First, Second);
}
int main()
{
static constexpr auto Multiply = [](const Integral auto First,
const Integral auto Second)
{ return First * Second; };
return Calculator<decltype(Multiply)>(15, 18);
}
I created an Integral concept that (just for dummy's sake) is satisfied if a type is convertible to int. I've created a calculator operation concept that accepts a lambda, two ints, and makes sure the operation returns an Integral.
I decided that I want the int in the concept to turn into an Integral, since I don't want only int's to be accepted to the operation (I want all integral types).
So I changed
requires(Operation&& op, int a, int b)
to
requires(Operation&& op, Integral&& a, Integral&& b)
Not only did this not work for me, I actually got 2 conflicting error messages (on GCC 10.1):
<source>:13:30: error: placeholder type not allowed in this context
<source>:13:30: error: expected 'auto' or 'decltype(auto)' after 'Integral'
13 | requires(Operation&& op, Integral&& a, Integral&& b)
I ran this using GodBolt's website Compiler Explorer. Whats going on here? Is there an actual way to do this?