Program Listing for File ciabatta.hpp
↰ Return to documentation for file (include/ciabatta/ciabatta.hpp
)
// Copyright 2019 Gašper Ažman
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* CHANGELOG:
* - Add explicit keyword to mixin constructor and remove
* default constructor and assignment operators.
* - Remove macro usage.
* - Invert the argument order on the curry struct template to
* support default template parameters.
* - Re-implement mixin struct so it doesn't require CRTP to compose a new mixin.
*/
#ifndef CIABATTA_CIABATTA_HPP
#define CIABATTA_CIABATTA_HPP
namespace ciabatta {
template <typename MostDerived>
struct ciabatta_top { /* not a mixin */
using self_type = MostDerived;
[[nodiscard]] decltype(auto) self() & { return static_cast<self_type&>(*this); }
[[nodiscard]] decltype(auto) self() && { return static_cast<self_type&&>(*this); }
[[nodiscard]] decltype(auto) self() const& { return static_cast<const self_type&>(*this); }
[[nodiscard]] decltype(auto) self() const&& { return static_cast<const self_type&&>(*this); }
};
struct deferred {
deferred() = delete;
};
namespace detail {
template <typename Concrete, template <class> class H, template <class> class... Tail>
struct chain_inherit {
using result = typename chain_inherit<Concrete, Tail...>::type;
using type = H<result>;
};
template <typename Concrete, template <class> class H>
struct chain_inherit<Concrete, H> {
using type = H<Concrete>;
};
template <typename Concrete, template <class> class... Mixins>
using mixin_impl = typename chain_inherit<ciabatta_top<Concrete>, Mixins...>::type;
} // namespace detail
template <typename Concrete, template <class> class... Mixins>
struct mixin_base : ::ciabatta::detail::mixin_impl<Concrete, Mixins...> {
template <typename... Rest>
constexpr explicit mixin_base(Rest&&... rest)
: ::ciabatta::detail::mixin_impl<Concrete, Mixins...>(static_cast<decltype(rest)>(rest)...) {}
};
template <template <class> class... Mixins>
struct mixin : ::ciabatta::mixin_base<mixin<Mixins...>, Mixins...> {
using ciabatta::mixin_base<mixin<Mixins...>, Mixins...>::mixin_base;
};
template <template <class...> class Mixin, typename... Args>
struct curry {
template <typename Base>
using mixin = Mixin<Base, Args...>;
};
template <typename Interface, typename Base = ::ciabatta::deferred>
struct provides : Base, Interface {
template <typename B>
using mixin = typename curry<provides, Interface>::template mixin<B>;
template <typename... Args>
constexpr explicit provides(Args&&... args) : Base(static_cast<decltype(args)>(args)...) {}
};
} // namespace ciabatta
#endif