Skip to content

Latest commit

 

History

History
253 lines (199 loc) · 7.31 KB

204.md

File metadata and controls

253 lines (199 loc) · 7.31 KB
Info

Example

static_assert(std::is_same_v<void, boost::mp11::mp_map_find<std::tuple<>, int>>);
static_assert(std::is_same_v<void, boost::mp11::mp_map_find<std::tuple<std::pair<int, double>>, double>>);
static_assert(std::is_same_v<std::pair<int, double>, boost::mp11::mp_map_find<std::tuple<std::pair<int, double>>, int>>);

https://godbolt.org/z/zh7488

Puzzle

  • Can you implement a user-friendly make routine which creates a given type with named parameters by leveraging a compile-time map?
template<template<class...> class T, class... Ts>
constexpr auto make(Ts...) { /*TODO*/ }

template<class TSize, class TValue>
struct foo {};

static_assert(std::is_same_v<foo<int, int>, decltype(make<foo>("size"_arg = int{}, "value"_arg = int{}))>);
static_assert(std::is_same_v<foo<int, int>, decltype(make<foo>("value"_arg = int{}, "size"_arg = int{}))>);
static_assert(std::is_same_v<foo<short, double>, decltype(make<foo>("size"_arg = short{}, "value"_arg = double{}))>);

https://godbolt.org/z/465xzr

Solutions

template <auto... Cs>
struct Arg {
  template <typename T>
  constexpr auto operator=(const T&) { return std::pair<Arg<Cs...>, T>{}; }
};

template <typename T, T... Cs>
constexpr auto operator""_arg() {
  return Arg<Cs...>{};
}

template<template<typename...> typename T, typename... Ts>
constexpr auto make(Ts...) {
    using map_t = boost::mp11::mp_list<Ts...>;
    using size_t = typename boost::mp11::mp_map_find<map_t, decltype("size"_arg)>::second_type;
    using value_t = typename boost::mp11::mp_map_find<map_t, decltype("value"_arg)>::second_type;
    return T<size_t, value_t>{};
}

https://godbolt.org/z/K6eznr

template< typename K>
struct KeyValue
{
    template< typename V>
    auto operator = ( V )
    {
        return std::pair<K,V>{};
    }
};

template<std::size_t N>
struct StaticString
{
    char str[N]{};
    constexpr StaticString ( char const(&p_str)[N] )
    {
        std::ranges::copy(p_str, str);
    };
    template<std::size_t M>
    constexpr bool operator == ( char const(&p_str)[M] ) const
    {
        return std::ranges::equal( p_str, str);
    }
};

struct value_type{};
struct size_type{};


template<StaticString ss>
constexpr auto operator""_arg()
{
    if constexpr(ss == "value")
        return KeyValue<value_type>{};
    else if constexpr( ss == "size" )
        return KeyValue<size_type>{};
}

template<template<class...> class T, class... Ts>
constexpr auto make(Ts...) {
    return T< typename boost::mp11::mp_map_find<std::tuple<Ts...>, size_type>::second_type
            , typename boost::mp11::mp_map_find<std::tuple<Ts...>, value_type>::second_type
            >{};
 }

https://godbolt.org/z/s9WMoj

template<auto Size>
struct fixed_string {
  char data[Size + 1]{};
  static constexpr auto size = Size;
  constexpr explicit(false) fixed_string(char const* str) { std::copy_n(str, Size + 1, data); }
  constexpr explicit(false) operator std::string_view() const { return {data, Size}; }
};
template<auto Size> fixed_string(char const (&)[Size]) -> fixed_string<Size - 1>;

template<auto...>
struct arg {
  template<class T> constexpr auto operator=(const T& t) const { return std::pair<arg, T>{*this, t}; }
};

template<fixed_string Str> constexpr auto operator""_arg() {
  return []<auto... Ns>(std::index_sequence<Ns...>) {
    return arg<Str.data[Ns]...>{};
  }(std::make_index_sequence<Str.size>{});
}

template<template<class...> class T, class... Ts>
constexpr auto make(Ts...) {
  using types_t = boost::mp11::mp_list<Ts...>;
  using size_t = typename boost::mp11::mp_map_find<types_t, decltype("siize"_arg)>::second_type;
  using value_t = typename boost::mp11::mp_map_find<types_t, decltype("value"_arg)>::second_type;
  return T<size_t, value_t>{};
}

https://godbolt.org/z/94qhrM

template<char... Cs> struct Name;

template<typename T, char ... Cs>
struct NamedType {
    using name = Name<Cs...>;
    using type = T;
};

template<char ...Cs>
struct Name {
    template<typename T> NamedType<T, Cs...> operator=(T) { return {}; }
};

template<typename Tchar, Tchar ... Cs> constexpr Name<Cs...> operator"" _arg() { return {}; }

template<template<class...> class T, class... Ts>
constexpr auto make(Ts...) {
    using map = std::tuple<std::pair<typename Ts::name, typename Ts::type>...>;
    using value = boost::mp11::mp_map_find<map, Name<'v','a','l','u','e'>>::second_type;
    using size = boost::mp11::mp_map_find<map, Name<'s','i','z','e'>>::second_type;
    return T<size,value>{};
}

https://godbolt.org/z/YK8GPW

namespace detail
{
    using boost::mp11::mp_second;
    using boost::mp11::mp_map_find;

    template<auto Size>
    struct fixed_string {
      using type = fixed_string;
        char data[Size + 1]{};
        static constexpr auto size = Size;
        constexpr fixed_string() = default;
        constexpr fixed_string(char const* str) { std::copy_n(str, Size + 1, data); }
    };

    template<auto Size> fixed_string(char const (&)[Size]) -> fixed_string<Size - 1>;

    template<auto...>
    struct arg
    {
        template <class T>
        constexpr std::pair<arg, T> operator=(T&& value) const { return {*this, value}; }
    };

    template<template<class...> class T>
    struct class_template {};

    template<template<class...> class T, template<class... Ts> class M>
    concept is_same_class_template_v = std::is_same_v<class_template<T>, class_template<M>>;

    namespace literal
    {
        template<fixed_string Fs> constexpr auto operator""_arg()
        {
            return []<auto... Ns>(std::index_sequence<Ns...>)
            {
                return arg<Fs.data[Ns]...>{};
            }(std::make_index_sequence<Fs.size>{});
        }

        template<fixed_string Fs> constexpr auto make_arg()
        {
            return []<auto... Ns>(std::index_sequence<Ns...>)
            {
                return arg<Fs.data[Ns]...>{};
            }(std::make_index_sequence<Fs.size>{});
        }
    }

    // for simplifying user-defined declarations below
    namespace helpers
    {
        template<template<class...> class T, template<class... Ts> class M>
        concept match = is_same_class_template_v<T, M>;

        template<template <class...> class T, class L, fixed_string... Ks>
        using unpack = T<typename mp_map_find<L, decltype(literal::make_arg<Ks>())>::second_type...>;

        template<class... Ts>
        using pack = std::tuple<Ts...>;
    }
}

using namespace detail::literal;
using namespace detail::helpers;

// user-defined template classes

template<class TSize, class TValue>
struct foo {};

template<class TOne, class TTwo>
struct bar {};

// user-defined declarations to define unpacking order of named arguments for template classes

template<template<class...> class T, class... Ts> requires match<T, foo>
constexpr unpack<T, pack<Ts...>, "size", "value"> make(Ts...) { return {}; }

template<template<class...> class T, class... Ts> requires match<T, bar>
constexpr unpack<T, pack<Ts...>, "one", "two"> make(Ts...) { return {}; }

https://godbolt.org/z/e15nzv