'Define a function signature containing a reference with C++20 Concepts
I am trying to use C++20 Concepts to constrain an interface. In this interface, I want a function signature to only use references. For some reason, I can't do this. Would someone help?
#include <concepts>
template <typename T>
concept MyInterface = requires(T t)
{
// How do I specify a f(int&) instead of f(int) here?
{t.f(int{})} -> std::integral;
};
struct X
{
int f(int& i) {
return i;
}
};
static_assert(MyInterface<X>);
/*
** While tempting, this is _NOT_ a solution. **
template <typename T>
concept MyInterface = requires(T t, int& i) // Add a requirement here.
{
{t.f(i)} -> std::integral;
};
// This will compile, despite allowing `i` to be an int.
// When really, it should be a int&.
X::f(int i) { return i };
*/
Solution 1:[1]
I disagree with this comment, this is absolutely a solution (except you don't have to make i an int&, int suffices):
template <typename T>
concept MyInterface = requires(T t, int i)
{
{t.f(i)} -> std::integral;
};
That is, indeed, your interface: you're passing an lvalue int into the member function f and you expect it to return some type which satisfies integral.
In order to reject callees taking int, you have to either pass some different type - like something convertible to int& instead of directly that:
template <typename T>
concept MyInterface = requires(T t, std::reference_wrapper<int> i)
{
{t.f(i)} -> std::integral;
};
or then additionally reject the other case:
template <typename T>
concept MyInterface =
requires(T t, int i) { {t.f(i)} -> std::integral; }
&& !requires(T t){ t.f(42); };
Passing reference_wrapper<int> is... ok. Explicitly rejecting taking int rvalues seems questionable at best.
Solution 2:[2]
You can utilize std::declval to create a reference type for the constraint:
template <typename T>
concept MyInterface = requires(T t)
{
{t.f(std::declval<int&>())} -> std::integral;
};
Note that this would still allow T::f(int) to work. To disallow it, you can add another constraint to it:
template <typename T>
concept MyInterface = requires(T t)
{
{t.f(std::declval<int&>())} -> std::integral;
}
&& !requires(T t)
{
{t.f(std::declval<int>())} -> std::integral;
};
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Barry |
| Solution 2 | Ranoiaetep |
