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
stdnamespace 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?