Skip to content

Latest commit

 

History

History
219 lines (168 loc) · 4.85 KB

325.md

File metadata and controls

219 lines (168 loc) · 4.85 KB
Info

Example

template <class...> struct foo {};
struct strong_typedef : foo<int, double> {};

template <fixed_string Str> struct named_strong_typedef;
template<fixed_string Str, class T> [[nodiscard]] constexpr auto typename_cast(const T& t);

int main() {
  strong_typedef s1{}; // strong typededf

  foo<int, double> f{};
  auto s2 = typename_cast<"foo">(f); // named strong typedef
}

https://godbolt.org/z/K4s6zhPKW

Puzzle

  • Can you implement a generic version of typename cast?
template <auto Str>
struct te;  // TODO

template <auto N, class T>
[[nodiscard]] constexpr auto typename_cast(T&&);  // TODO

template <class...>
struct foo {};

template <class... Ts>
constexpr auto fn() {
    foo<Ts...> f{};
    return typename_cast</*TODO*/ 0>(f);
}

template <class>
constexpr auto is_te_v = false;
template <auto N>
constexpr auto is_te_v<te<N>> = true;

static_assert(std::is_base_of_v<foo<>, decltype(fn())>);
static_assert(is_te_v<decltype(fn())>);
static_assert(not std::is_base_of_v<foo<>, decltype(fn<int>())>);

static_assert(std::is_base_of_v<foo<int>, decltype(fn<int>())>);
static_assert(is_te_v<decltype(fn<int>())>);
static_assert(not std::is_base_of_v<foo<double>, decltype(fn<int>())>);

static_assert(typeid(fn<int>()) == typeid(fn<int>()));
static_assert(typeid(fn<int>()) != typeid(fn<double>()));

https://godbolt.org/z/fxvKvo9dY

Solutions

template <int N>
struct types {
    friend auto get(types<N>);
};

template <int N, class T>
struct set_type {
    friend auto get(types<N>) { return T{}; }
    static constexpr auto value = true;
};

template <int N>
struct te : decltype(get(types<N>{})) {};

template <int N, class T>
[[nodiscard]] constexpr auto typename_cast(const T &v) {
    static_assert(set_type<N, T>::value);
    return static_cast<te<N>>(v);
}

template <class...>
struct foo {};

template <class... Ts>
constexpr auto fn() {
    foo<Ts...> f{};
    constexpr std::string_view str = __PRETTY_FUNCTION__;
    constexpr auto hash =
        std::accumulate(str.begin(), str.end(), 0,
                        [](auto acc, auto c) { return (acc << CHAR_BIT) ^ c; });
    return typename_cast<hash>(f);
}

https://godbolt.org/z/arz7ehjde

template <auto Key>
struct Type_name {
    friend auto lookup(Type_name);

    template <typename T>
    struct Store {
        friend auto lookup(Type_name) { return T{}; }
    };
};

template <auto Key>
struct Erased : decltype(lookup(Type_name<Key>())) {};

template <auto Key, class T>
[[nodiscard]] constexpr auto typename_cast(T&& x) {
    void(typename Type_name<Key>::template Store<std::remove_cvref_t<T>>{});
    return static_cast<Erased<Key>>(x);
}

template <class...>
struct foo {};

template <typename... Ts>
constexpr std::size_t key() {
    std::size_t result{};
    for (auto c : __PRETTY_FUNCTION__) (result ^= c) <<= 1;
    return result;
}

static_assert(key<int>() != key<double>());

template <class... Ts>
constexpr auto fn() {
    foo<Ts...> f{};
    return typename_cast<key<Ts...>()>(f);
}

https://godbolt.org/z/M5qsvqsxn

template <auto Str>
struct types final {
    friend auto get(types);
    template <class T>
    struct set {
        friend auto get(types) { return T{}; }
    };
};

template <auto Str>
struct te : decltype(get(types<Str>{})) {};

template <class T, auto N>
[[nodiscard]] constexpr auto typename_cast(T&& t) {
    void(typename types<N>::template set<T>{});
    return static_cast<te<N>>(std::forward<T>(t));
}

template <class...>
struct foo {};

template <class... Ts>
constexpr auto fn() {
    foo<Ts...> f{};
    return typename_cast<decltype(f), (sizeof(Ts) + ... + 0)>(std::move(f));
}

https://godbolt.org/z/bnforGcf1

template <typename T>
constexpr size_t comptime_typeid() {
    constexpr std::string_view func_name = __PRETTY_FUNCTION__;
    // djb2 string hashing
    size_t hash = 5381;
    for (char c : func_name) {
        hash = ((hash << 5) + hash) + c;
    }
    return hash;
}

template <size_t N>
struct types final {
    friend auto get(types<N>);

    template <class T>
    struct set {
        friend auto get(types<N>) { return T{}; }
    };
};

template <size_t N>
struct te : decltype(get(types<N>{})) {};

template <size_t N, class T>
[[nodiscard]] constexpr auto typename_cast(T&& t) {
    void(typename types<N>::template set<T>{});
    return static_cast<te<N>>(t);
}

template <class...>
struct foo {};

template <class... Ts>
constexpr auto fn() {
    foo<Ts...> f{};
    constexpr auto id = comptime_typeid<decltype(f)>();
    return typename_cast<id>(std::move(f));

https://godbolt.org/z/PsW8GKoT5