I am currently trying to get my feet wet with concepts. Let us assume that I have a concept:
template <class T> concept Initable = requires (T&t) { { init(t) }; };
// just for demonstration purposes, real concept makes more sense ...
and I want to provide an adoption layer for a third-party class like std::optional
to implement this concept, what would be the most seemless way for me to do so?
Obviously, the following piece of code fails:
template <std::semiregular T>
T& init(std::optional<T> &v) { /* contents not that important */ v = T{}; return *v; }
static_assert(Initable<std::optional<int>>, "Oh no!"); // Fails!
The reason is two-phase lookup.
When trying to resolve init
in the Initable
concept during phase 1, my definition of init
is not available, because it is provided below the Initable
concept.
When trying to resolve it during phase 2, my definition is not found via argument-dependent lookup, because it is not provided in the std
namespace.
Two obvious solutions, thus, would be to either provide the definition of init
before defining the Initable
concept or move init
to the std
namespace.
But I want to implement that concept for std::optional
without
- relying on a particular definition/include order,
- populating the
std
namespace and - using too much boiler-plate code at the caller site.
What would be the best way to do so? Could I make it somewhat easier to accomplish this when defining the Initable
concept?
Basically I am asking, is this possible?
#include <concepts>
#include <optional>
template <class T>
concept Initable =
requires (T& t) { init(t); } // May be changed to make the task easier.
;
// Insert code *here* that magically makes std::optional implement Initable.
static_assert(Initable<std::optional<int>>, "std::optional is not initable!");
And, if not, what would be the next best thing?