Info
-
Did you know that lambda expression is guaranteed to have a unique type?
Example
static_assert(typeid([]{}) != typeid([]{}));
template<auto = []{}>
struct foo{};
foo f1, f2;
static_assert(typeid(f1) != typeid(f2));
Puzzle
-
Can you implement
create
which creates given type as a unique type or same type?- Note: For type uniqueness inheritance might be used
class same;
class unique;
template<class...>
[[nodiscard]] constexpr auto create(); // TODO
struct foo {};
static_assert(typeid(create<foo>()) == typeid(create<foo>()));
static_assert(typeid(create<foo, class unique>()) != typeid(create<foo, class unique>()));
Solutions
template <typename T, auto UniqueTag>
struct wrap_unique: T {};
template<class T, typename UniqueOrSame = class same, auto UniqueTag = []{}>
[[nodiscard]] constexpr std::convertible_to<T> auto create()
{
if constexpr (std::same_as<UniqueOrSame, class unique>) {
return wrap_unique<T, UniqueTag>{};
} else {
return T{};
}
}
template <class T, auto = []{}>
struct uniquify : T {};
template <class T, class C = same, class U = uniquify<T>>
[[nodiscard]] constexpr auto create()
-> std::conditional_t<std::same_as<C, unique>, U, T>;
template <class T, auto>
struct uniquify : T {};
template <class T, class U = same, auto V = [] {}>
[[nodiscard]] constexpr auto create() {
if constexpr (std::same_as<U, unique>) {
return uniquify<T, V>{};
} else {
return T{};
}
}
template<class T, class U = same, auto UniqueLambda = []{}>
[[nodiscard]] constexpr auto create() {
if constexpr (std::is_same_v<U, unique>) {
return UniqueLambda;
}
}
template <class first, class second = same, auto = [] {}>
[[nodiscard]] constexpr auto create() {
if constexpr (std::is_same_v<second, same>) {
return first{};
} else {
return [] {};
}
}
template<class Tp, auto = []{}>
class Holder : Tp {};
template<class Tp, class Option = same, class Held = Holder<Tp> >
[[nodiscard]] constexpr auto create() {
if constexpr (std::is_same_v<Option, same>)
return Tp{};
else
return Held{};
}
template <class T, auto = []{}>
class diff : T{};
template<class T, class U = same, class V = diff<T>>
[[nodiscard]] constexpr auto create(){
if constexpr(std::is_same_v<U, unique>){
return V{};
}
}