Skip to content

Latest commit

 

History

History
290 lines (237 loc) · 7.69 KB

207.md

File metadata and controls

290 lines (237 loc) · 7.69 KB
Info

Example

#if __cpp_has_constexpr_function_parameters
  void foo(constexpr int x) {
    static_assert(42 == x);
  }

  int main() {
    foo(42);
  }
#else
  template<int x> void foo() {
    static_assert(42 == x);
  }

  int main() {
    foo<42>();
  }
#endif

https://godbolt.org/z/ojrqd7

Puzzle

  • Can you implement a compile-time and run-time map-like accessors for tuple?
template<char...> constexpr auto operator""_id(); // TODO
template<class...> struct tuple; // TODO

int main() {
  using namespace boost::ut;

  "compile-time tuple map-like access"_test = [] {
    constexpr tuple ct{42, [](auto x){ return x; }};
    expect(constant<42_i == ct[0_id]>);
    expect(constant<43_i == ct[1_id](43)>);
  };

  "run-time tuple map-like access"_test = [] {
    const tuple rt = tuple{1, 2.0};
    expect(throws<std::bad_cast>([&rt]{std::any_cast<float>(rt[1]);}));
    expect(1_i == std::any_cast<int>(rt[0]));
    expect(2.0_d == std::any_cast<double>(rt[1]));
  };
}

https://godbolt.org/z/8vGqj3

Solutions

template<char... Cs> constexpr auto operator""_id() {
  constexpr std::array chars{Cs...};
  constexpr auto index = std::reduce(std::cbegin(chars), std::cend(chars), 0,
                                     [] (const auto i, const auto digit) { return i * 10 + (digit - '0'); });
  return std::integral_constant<int, index>{};
}

template<class... Ts> struct tuple : std::tuple<Ts...> {
  using std::tuple<Ts...>::tuple;

  template <class T, auto N>
  constexpr const auto& operator[](std::integral_constant<T, N>) const {
    return std::get<N>(*this);
  }

  constexpr const auto operator[](int i) const {
    return [&] <auto... Is> (std::index_sequence<Is...>) {
      using F = auto (*)(const tuple<Ts...>&) -> std::any;
      constexpr std::array<F, sizeof...(Is)> fs{
        [] (const auto& t) -> std::any { return t[std::integral_constant<int, Is>{}]; }...
      };
      return fs[i](*this);
    }(std::index_sequence_for<Ts...>{});
  }
};

template <class... Ts>
tuple(Ts...) -> tuple<Ts...>;

https://godbolt.org/z/GaPYcb

template<char... Cs>
constexpr auto operator""_id() {
  return []<auto... Ns>(std::index_sequence<Ns...>) {
    return std::integral_constant<int, ((int(std::pow(10, sizeof...(Ns) - Ns - 1)) * (Cs - '0')) + ...)>{};
  }(std::make_index_sequence<sizeof...(Cs)>{});
}

template<class... Ts>
struct tuple : std::tuple<Ts...> {
  using std::tuple<Ts...>::tuple;

  template<class TId> constexpr decltype(auto) operator[](const TId id) const {
    if constexpr (std::is_integral_v<TId>) {
      return std::apply([id](auto... args) { return std::array{std::any{args}...}[id];  }, std::tuple<Ts...>(*this));
    } else {
      return std::get<TId{}>(*this);
    }
  }
};
template<class... Ts> tuple(Ts...) -> tuple<Ts...>;

https://godbolt.org/z/vMWaa9

using integer_t = int;

namespace details {  // Intentionally using details instead of detail to avoid
                     // ambiguous namespace
[[nodiscard]] constexpr auto apply_power(const auto power, const auto val) {
  return static_cast<integer_t>(std::pow(10, power)) * (val - '0');
}
}  // namespace details

template <char... Cs>
[[nodiscard]] constexpr auto operator""_id() {
  constexpr auto num_chars = sizeof...(Cs);

  return []<auto... Is>(const std::index_sequence<Is...>) {
    return std::integral_constant<
        integer_t, (details::apply_power(num_chars - Is - 1, Cs) + ...)>{};
  }
  (std::make_index_sequence<num_chars>{});
};

template <class... Ts>
struct tuple : std::tuple<Ts...> {
  using std::tuple<Ts...>::tuple;

  template <auto Index>
  [[nodiscard]] constexpr auto operator[](
      const std::integral_constant<integer_t, Index>) const {
    return std::get<Index>(*this);
  }

  [[nodiscard]] constexpr auto operator[](const auto index) const {
    return boost::mp11::mp_with_index<sizeof...(Ts)>(
        index, [&](const auto I) { return std::any(std::get<I>(*this)); });
  }
};
template <class... Ts>
tuple(Ts...) -> tuple<Ts...>;

https://godbolt.org/z/oKn8zs

template < char ... str >
constexpr auto stoi = []()
{
    constexpr int N = sizeof ... (str) ;
    return []<auto ... Is> ( std::index_sequence< Is ... > ){
        std::size_t m = std::pow( 10, N );//not constexpr but works under gcc
        return ( 0 + ... + ( ( str - '0') * (m/=10)  )  );
    }( std::make_index_sequence<N>{} );
} ();

template< char ... str > constexpr auto operator""_id()
{
    return std::index_sequence< stoi<str...> >{} ;
}

template <class T, class ... Ts >
struct tuple:tuple<Ts...>
{
    constexpr tuple(T data, Ts... datas):tuple<Ts...>(datas...),data{data}{}
    T data;
    std::any operator[]( int i ) const
    {
        if ( i == 0)
            return data;
        else
            return tuple<Ts...>::operator[](i-1);
    }
    template<std::size_t I>
    constexpr auto operator[]( std::index_sequence<I> )  const
    {
        if constexpr ( I == 0 ){
            return data;
        } else
        {
            return tuple<Ts...>::operator[](std::index_sequence<I-1>{});
        }
    }
};
template <class T>
struct tuple<T>
{
    std::any operator[]( int ) const
    {
        return data;
    }
    template<std::size_t I>
    constexpr auto operator[]( std::index_sequence<I> ) const
    {
        return data;
    }

    T data;
};

https://godbolt.org/z/89f9eb

namespace detail {
    template<class T, char C, char... Cs>
    consteval T make_integer_constant() {
        if constexpr (sizeof...(Cs) == 0) return C - '0';
        else return make_integer_constant<T, C>() * 10 + make_integer_constant<T, Cs...>();
    }
} // namespace detail

template<char... Cs>
consteval auto operator""_id() {
    constexpr auto value = detail::make_integer_constant<std::size_t, Cs...>();
    return std::integral_constant<std::remove_cvref_t<decltype(value)>, value>{};
}

template<class... Ts>
struct tuple {
    constexpr tuple(Ts&&... args) : t{std::forward<Ts>(args)...} {}

    // compile-time
    template<std::size_t I>
    constexpr auto operator[] (std::integral_constant<std::size_t, I>) const {
        return std::get<I>(t);
    }

    // run-time
    constexpr auto operator[] (std::size_t i) const {
        return [&] <std::size_t... Is> (std::index_sequence<Is...>) {
            constexpr std::array<std::any(*)(const tuple&), sizeof...(Is)> fs{
                [] (const auto& t) -> std::any { return t[std::integral_constant<std::size_t, Is>{}]; }...
            };

            return fs[i](*this);
        }(std::index_sequence_for<Ts...>{});
    }

private:
    std::tuple<Ts...> t;
};

https://godbolt.org/z/1zGrnY

template<int I> struct Id{};

template<char...Cs> constexpr auto operator""_id() {
    constexpr std::array<int, sizeof...(Cs)> digits{Cs-'0'...};
    constexpr int number = std::accumulate(digits.begin(), digits.end(), 0, [](auto a, auto b) { return 10*a+b;});
    return Id<number>{};
}

template<class Tp, size_t N=0>
std::any runtime_get(Tp const& tp, size_t idx) {
    if(N==idx)
        return std::get<N>(tp);
    if constexpr( N+1 < std::tuple_size_v<Tp>)
        return runtime_get<Tp, N+1>(tp, idx);
    return {};
}

template<class...Args> struct tuple : std::tuple<Args...> {
    constexpr tuple(Args...args) : std::tuple<Args...>(args...) {}
    template<int I> constexpr auto operator[](Id<I>) const { return std::get<I>(*this); }
    auto operator[](int I) const { return runtime_get(static_cast<std::tuple<Args...>>(*this),I); }
};

https://godbolt.org/z/z77Tdn