/* * Copyright 2017-present Facebook, Inc. * * 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. */ // TODO: [x] "cast" from Poly to Poly // TODO: [ ] copy/move from Poly/Poly to Poly // TODO: [ ] copy-on-write? // TODO: [ ] down- and cross-casting? (Possible?) // TODO: [ ] shared ownership? (Dubious.) // TODO: [ ] can games be played with making the VTable a member of a struct // with strange alignment such that the address of the VTable can // be used to tell whether the object is stored in-situ or not? #pragma once #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 #error Folly.Poly requires gcc-5 or greater #endif #include #include #include #include #include #include #include #include #include #include #if !defined(__cpp_inline_variables) #define FOLLY_INLINE_CONSTEXPR constexpr #else #define FOLLY_INLINE_CONSTEXPR inline constexpr #endif #include #include namespace folly { template struct Poly; /** * Within the definition of interface `I`, `PolySelf` is an alias for * the instance of `Poly` that is currently being instantiated. It is * one of: `Poly`, `Poly`, `Poly`, or `Poly`; where * `J` is either `I` or some interface that extends `I`. * * It can be used within interface definitions to declare members that accept * other `Poly` objects of the same type as `*this`. * * The first parameter may optionally be cv- and/or reference-qualified, in * which case, the qualification is applies to the type of the interface in the * resulting `Poly<>` instance. The second template parameter controls whether * or not the interface is decayed before the cv-ref qualifiers of the first * argument are applied. For example, given the following: * * struct Foo { * template * struct Interface : Base { * using A = PolySelf; * using B = PolySelf; * using C = PolySelf; * using X = PolySelf; * using Y = PolySelf; * using Z = PolySelf; * }; * // ... * }; * struct Bar : PolyExtends { * // ... * }; * * Then for `Poly`, the typedefs are aliases for the following types: * - `A` is `Poly` * - `B` is `Poly` * - `C` is `Poly` * - `X` is `Poly` * - `Y` is `Poly` * - `Z` is `Poly` * * And for `Poly`, the typedefs are aliases for the following types: * - `A` is `Poly` * - `B` is `Poly` * - `C` is `Poly` * - `X` is `Poly` * - `Y` is `Poly` * - `Z` is `Poly` */ template < class Node, class Tfx = detail::MetaIdentity, class Access = detail::PolyAccess> using PolySelf = decltype(Access::template self_()); /** * When used in conjunction with `PolySelf`, controls how to construct `Poly` * types related to the one currently being instantiated. * * \sa PolySelf */ using PolyDecay = detail::MetaQuote; #if !defined(__cpp_template_auto) /** * Use `FOLLY_POLY_MEMBERS(MEMS...)` on pre-C++17 compilers to specify a * comma-separated list of member function bindings. * * For example: * * struct IFooBar { * template * struct Interface : Base { * int foo() const { return folly::poly_call<0>(*this); } * void bar() { folly::poly_call<1>(*this); } * }; * template * using Members = FOLLY_POLY_MEMBERS(&T::foo, &T::bar); * }; */ #define FOLLY_POLY_MEMBERS(...) \ typename decltype(::folly::detail::deduceMembers( \ __VA_ARGS__))::template Members<__VA_ARGS__> /** * Use `FOLLY_POLY_MEMBER(SIG, MEM)` on pre-C++17 compilers to specify a member * function binding that needs to be disambiguated because of overloads. `SIG` * should the (possibly const-qualified) signature of the `MEM` member function * pointer. * * For example: * * struct IFoo { * template struct Interface : Base { * int foo() const { return folly::poly_call<0>(*this); } * }; * template using Members = FOLLY_POLY_MEMBERS( * // This works even if T::foo is overloaded: * FOLLY_POLY_MEMBER(int()const, &T::foo) * ); * }; */ #define FOLLY_POLY_MEMBER(SIG, MEM) \ ::folly::detail::MemberDef< \ ::folly::detail::Member(MEM)), MEM>>::value /** * A list of member function bindings. */ template using PolyMembers = detail::TypeList; #else #define FOLLY_POLY_MEMBER(SIG, MEM) ::folly::sig(MEM) #define FOLLY_POLY_MEMBERS(...) ::folly::PolyMembers<__VA_ARGS__> template struct PolyMembers {}; #endif /** * Used in the definition of a `Poly` interface to say that the current * interface is an extension of a set of zero or more interfaces. * * Example: * * struct IFoo { * template struct Interface : Base { * void foo() { folly::poly_call<0>(*this); } * }; * template using Members = FOLLY_POLY_MEMBERS(&T::foo); * } * struct IBar : PolyExtends { * template struct Interface : Base { * void bar(int i) { folly::poly_call<0>(*this, i); } * }; * template using Members = FOLLY_POLY_MEMBERS(&T::bar); * } */ template struct PolyExtends : virtual I... { using Subsumptions = detail::TypeList; template struct Interface : Base { Interface() = default; using Base::Base; }; template using Members = PolyMembers<>; }; //////////////////////////////////////////////////////////////////////////////// /** * Call the N-th member of the currently-being-defined interface. When the * first parameter is an object of type `PolySelf` (as opposed to `*this`) * you must explicitly specify which interface through which to dispatch. * For instance: * * struct IAddable { * template * struct Interface : Base { * friend PolySelf * operator+(PolySelf const& a, PolySelf const& b) { * return folly::poly_call<0, IAddable>(a, b); * } * }; * template * static auto plus_(T const& a, T const& b) -> decltype(a + b) { * return a + b; * } * template * using Members = FOLLY_POLY_MEMBERS(&plus_>); * }; * * \sa PolySelf */ template auto poly_call(This&& _this, As&&... as) -> decltype(detail::PolyAccess::call( static_cast(_this), static_cast(as)...)) { return detail::PolyAccess::call( static_cast(_this), static_cast(as)...); } /// \overload template decltype(auto) poly_call(detail::PolyNode&& _this, As&&... as) { using This = detail::InterfaceOf>; return detail::PolyAccess::call( static_cast(_this), static_cast(as)...); } /// \overload template decltype(auto) poly_call(detail::PolyNode& _this, As&&... as) { using This = detail::InterfaceOf>; return detail::PolyAccess::call( static_cast(_this), static_cast(as)...); } /// \overload template decltype(auto) poly_call(detail::PolyNode const& _this, As&&... as) { using This = detail::InterfaceOf>; return detail::PolyAccess::call( static_cast(_this), static_cast(as)...); } /// \overload template < std::size_t N, class I, class Poly, typename... As, std::enable_if_t::value, int> = 0> auto poly_call(Poly&& _this, As&&... as) -> decltype(poly_call( static_cast(_this).get(), static_cast(as)...)) { return poly_call( static_cast(_this).get(), static_cast(as)...); } /// \cond /// \overload template [[noreturn]] detail::Bottom poly_call(detail::ArchetypeBase const&, As&&...) { assume_unreachable(); } /// \endcond //////////////////////////////////////////////////////////////////////////////// /** * Try to cast the `Poly` object to the requested type. If the `Poly` stores an * object of that type, return a reference to the object; otherwise, throw an * exception. * \tparam T The (unqualified) type to which to cast the `Poly` object. * \tparam Poly The type of the `Poly` object. * \param that The `Poly` object to be cast. * \return A reference to the `T` object stored in or refered to by `that`. * \throw BadPolyAccess if `that` is empty. * \throw BadPolyCast if `that` does not store or refer to an object of type * `T`. */ template detail::AddCvrefOf&& poly_cast(detail::PolyRoot&& that) { return detail::PolyAccess::cast(std::move(that)); } /// \overload template detail::AddCvrefOf& poly_cast(detail::PolyRoot& that) { return detail::PolyAccess::cast(that); } /// \overload template detail::AddCvrefOf const& poly_cast(detail::PolyRoot const& that) { return detail::PolyAccess::cast(that); } /// \cond /// \overload template [[noreturn]] detail::AddCvrefOf&& poly_cast(detail::ArchetypeRoot&&) { assume_unreachable(); } /// \overload template [[noreturn]] detail::AddCvrefOf& poly_cast(detail::ArchetypeRoot&) { assume_unreachable(); } /// \overload template [[noreturn]] detail::AddCvrefOf const& poly_cast( detail::ArchetypeRoot const&) { assume_unreachable(); } /// \endcond /// \overload template < class T, class Poly, std::enable_if_t::value, int> = 0> constexpr auto poly_cast(Poly&& that) -> decltype(poly_cast(std::declval().get())) { return poly_cast(static_cast(that).get()); } //////////////////////////////////////////////////////////////////////////////// /** * Returns a reference to the `std::type_info` object corresponding to the * object currently stored in `that`. If `that` is empty, returns * `typeid(void)`. */ template std::type_info const& poly_type(detail::PolyRoot const& that) noexcept { return detail::PolyAccess::type(that); } /// \cond /// \overload [[noreturn]] inline std::type_info const& poly_type( detail::ArchetypeBase const&) noexcept { assume_unreachable(); } /// \endcond /// \overload template ::value, int> = 0> constexpr auto poly_type(Poly const& that) noexcept -> decltype(poly_type(that.get())) { return poly_type(that.get()); } //////////////////////////////////////////////////////////////////////////////// /** * Returns `true` if `that` is not currently storing an object; `false`, * otherwise. */ template bool poly_empty(detail::PolyRoot const& that) noexcept { return detail::State::eEmpty == detail::PolyAccess::vtable(that)->state_; } /// \overload template constexpr bool poly_empty(detail::PolyRoot const&) noexcept { return false; } /// \overload template constexpr bool poly_empty(detail::PolyRoot const&) noexcept { return false; } /// \overload template constexpr bool poly_empty(Poly const&) noexcept { return false; } /// \overload template constexpr bool poly_empty(Poly const&) noexcept { return false; } /// \cond [[noreturn]] inline bool poly_empty(detail::ArchetypeBase const&) noexcept { assume_unreachable(); } /// \endcond //////////////////////////////////////////////////////////////////////////////// /** * Given a `Poly`, return a `Poly`. Otherwise, when `I` is not a * reference type, returns a `Poly&&` when given a `Poly&`, like * `std::move`. */ template < class I, std::enable_if_t>::value, int> = 0> constexpr Poly&& poly_move(detail::PolyRoot& that) noexcept { return static_cast&&>(static_cast&>(that)); } /// \overload template < class I, std::enable_if_t>::value, int> = 0> Poly poly_move(detail::PolyRoot const& that) noexcept { return detail::PolyAccess::move(that); } /// \overload template Poly poly_move(detail::PolyRoot const& that) noexcept { return detail::PolyAccess::move(that); } /// \cond /// \overload [[noreturn]] inline detail::ArchetypeBase poly_move( detail::ArchetypeBase const&) noexcept { assume_unreachable(); } /// \endcond /// \overload template ::value, int> = 0> constexpr auto poly_move(Poly& that) noexcept -> decltype(poly_move(that.get())) { return poly_move(that.get()); } /// \cond namespace detail { /** * The implementation for `Poly` for when the interface type is not * reference-like qualified, as in `Poly`. */ template struct PolyVal : PolyImpl { private: friend PolyAccess; struct NoneSuch {}; using Copyable = std::is_copy_constructible>; using PolyOrNonesuch = If; using PolyRoot::vptr_; PolyRoot& _polyRoot_() noexcept { return *this; } PolyRoot const& _polyRoot_() const noexcept { return *this; } Data* _data_() noexcept { return PolyAccess::data(*this); } Data const* _data_() const noexcept { return PolyAccess::data(*this); } public: /** * Default constructor. * \post `poly_empty(*this) == true` */ PolyVal() = default; /** * Move constructor. * \post `poly_empty(that) == true` */ PolyVal(PolyVal&& that) noexcept; /** * A copy constructor if `I` is copyable; otherwise, a useless constructor * from a private, incomplete type. */ /* implicit */ PolyVal(PolyOrNonesuch const& that); ~PolyVal(); /** * Inherit any constructors defined by any of the interfaces. */ using PolyImpl::PolyImpl; /** * Copy assignment, destroys the object currently held (if any) and makes * `*this` equal to `that` by stealing its guts. */ Poly& operator=(PolyVal that) noexcept; /** * Construct a Poly from a concrete type that satisfies the I concept */ template ::value, int> = 0> /* implicit */ PolyVal(T&& t); /** * Construct a `Poly` from a compatible `Poly`. "Compatible" here means: the * other interface extends this one either directly or indirectly. */ template ::value, int> = 0> /* implicit */ PolyVal(Poly that); /** * Assign to this `Poly` from a concrete type that satisfies the `I` * concept. */ template ::value, int> = 0> Poly& operator=(T&& t); /** * Assign a compatible `Poly` to `*this`. "Compatible" here means: the * other interface extends this one either directly or indirectly. */ template ::value, int> = 0> Poly& operator=(Poly that); /** * Swaps the values of two `Poly` objects. */ void swap(Poly& that) noexcept; }; //////////////////////////////////////////////////////////////////////////////// /** * The implementation of `Poly` for when the interface type is * reference-quelified, like `Poly`. */ template struct PolyRef : private PolyImpl { private: friend PolyAccess; AddCvrefOf, I>& _polyRoot_() const noexcept; Data* _data_() noexcept { return PolyAccess::data(*this); } Data const* _data_() const noexcept { return PolyAccess::data(*this); } static constexpr RefType refType() noexcept; protected: template PolyRef(That&& that, Type); public: /** * Copy constructor * \post `&poly_cast(*this) == &poly_cast(that)`, where `T` is the * type of the object held by `that`. */ PolyRef(PolyRef const& that) noexcept; /** * Copy assignment * \post `&poly_cast(*this) == &poly_cast(that)`, where `T` is the * type of the object held by `that`. */ Poly& operator=(PolyRef const& that) noexcept; /** * Construct a `Poly` from a concrete type that satisfies concept `I`. * \post `!poly_empty(*this)` */ template ::value, int> = 0> /* implicit */ PolyRef(T&& t) noexcept; /** * Construct a `Poly` from a compatible `Poly`. */ template < class I2, std::enable_if_t::value, int> = 0> /* implicit */ PolyRef(Poly&& that) noexcept( std::is_reference::value); template < class I2, std::enable_if_t::value, int> = 0> /* implicit */ PolyRef(Poly& that) noexcept(std::is_reference::value) : PolyRef{that, Type{}} {} template < class I2, std::enable_if_t::value, int> = 0> /* implicit */ PolyRef(Poly const& that) noexcept( std::is_reference::value) : PolyRef{that, Type{}} {} /** * Assign to a `Poly` from a concrete type that satisfies concept `I`. * \post `!poly_empty(*this)` */ template ::value, int> = 0> Poly& operator=(T&& t) noexcept; /** * Assign to `*this` from another compatible `Poly`. */ template < class I2, std::enable_if_t::value, int> = 0> Poly& operator=(Poly&& that) noexcept(std::is_reference::value); /** * \overload */ template < class I2, std::enable_if_t::value, int> = 0> Poly& operator=(Poly& that) noexcept(std::is_reference::value); /** * \overload */ template < class I2, std::enable_if_t::value, int> = 0> Poly& operator=(Poly const& that) noexcept( std::is_reference::value); /** * Swap which object this `Poly` references ("shallow" swap). */ void swap(Poly& that) noexcept; /** * Get a reference to the interface, with correct `const`-ness applied. */ AddCvrefOf, I>& get() const noexcept; /** * Get a reference to the interface, with correct `const`-ness applied. */ AddCvrefOf, I>& operator*() const noexcept { return get(); } /** * Get a pointer to the interface, with correct `const`-ness applied. */ auto operator-> () const noexcept { return &get(); } }; template using PolyValOrRef = If::value, PolyRef, PolyVal>; } // namespace detail /// \endcond /** * `Poly` is a class template that makes it relatively easy to define a * type-erasing polymorphic object wrapper. * * \par Type-erasure * * \par * `std::function` is one example of a type-erasing polymorphic object wrapper; * `folly::exception_wrapper` is another. Type-erasure is often used as an * alternative to dynamic polymorphism via inheritance-based virtual dispatch. * The distinguishing characteristic of type-erasing wrappers are: * \li **Duck typing:** Types do not need to inherit from an abstract base * class in order to be assignable to a type-erasing wrapper; they merely * need to satisfy a particular interface. * \li **Value semantics:** Type-erasing wrappers are objects that can be * passed around _by value_. This is in contrast to abstract base classes * which must be passed by reference or by pointer or else suffer from * _slicing_, which causes them to lose their polymorphic behaviors. * Reference semantics make it difficult to reason locally about code. * \li **Automatic memory management:** When dealing with inheritance-based * dynamic polymorphism, it is often necessary to allocate and manage * objects on the heap. This leads to a proliferation of `shared_ptr`s and * `unique_ptr`s in APIs, complicating their point-of-use. APIs that take * type-erasing wrappers, on the other hand, can often store small objects * in-situ, with no dynamic allocation. The memory management, if any, is * handled for you, and leads to cleaner APIs: consumers of your API don't * need to pass `shared_ptr`; they can simply pass any object * that satisfies the interface you require. (`std::function` is a * particularly compelling example of this benefit. Far worse would be an * inheritance-based callable solution like * `shared_ptr>`. ) * * \par Example: Defining a type-erasing function wrapper with `folly::Poly` * * \par * Defining a polymorphic wrapper with `Poly` is a matter of defining two * things: * \li An *interface*, consisting of public member functions, and * \li A *mapping* from a concrete type to a set of member function bindings. * * Below is a (heavily commented) example of a simple implementation of a * `std::function`-like polymorphic wrapper. Its interface has only a simgle * member function: `operator()` * * // An interface for a callable object of a particular signature, Fun * // (most interfaces don't need to be templates, FWIW). * template * struct IFunction; * * template * struct IFunction { * // An interface is defined as a nested class template called * // Interface that takes a single template parameter, Base, from * // which it inherits. * template * struct Interface : Base { * // The Interface has public member functions. These become the * // public interface of the resulting Poly instantiation. * // (Implementation note: Poly> will publicly * // inherit from this struct, which is what gives it the right * // member functions.) * R operator()(As... as) const { * // The definition of each member function in your interface will * // always consist of a single line dispatching to * // folly::poly_call. The "N" corresponds to the N-th member * // function in the list of member function bindings, Members, * // defined below. The first argument will always be *this, and the * // rest of the arguments should simply forward (if necessary) the * // member function's arguments. * return static_cast( * folly::poly_call<0>(*this, std::forward(as)...)); * } * }; * * // The "Members" alias template is a comma-separated list of bound * // member functions for a given concrete type "T". The * // "FOLLY_POLY_MEMBERS" macro accepts a comma-separated list, and the * // (optional) "FOLLY_POLY_MEMBER" macro lets you disambiguate overloads * // by explicitly specifying the function signature the target member * // function should have. In this case, we require "T" to have a * // function call operator with the signature `R(As...) const`. * // * // If you are using a C++17-compatible compiler, you can do away with * // the macros and write this as: * // * // template * // using Members = folly::PolyMembers< * // folly::sig(&T::operator())>; * // * // And since `folly::sig` is only needed for disambiguation in case of * // overloads, if you are not concerned about objects with overloaded * // function call operators, it could be further simplified to: * // * // template * // using Members = folly::PolyMembers<&T::operator()>; * // * template * using Members = FOLLY_POLY_MEMBERS( * FOLLY_POLY_MEMBER(R(As...) const, &T::operator())); * }; * * // Now that we have defined the interface, we can pass it to Poly to * // create our type-erasing wrapper: * template * using Function = Poly>; * * \par * Given the above definition of `Function`, users can now initialize instances * of (say) `Function` with function objects like * `std::plus` and `std::multiplies`, as below: * * Function fun = std::plus{}; * assert(5 == fun(2, 3)); * fun = std::multiplies{}; * assert(6 = fun(2, 3)); * * \par Defining an interface with C++17 * * \par * With C++17, defining an interface to be used with `Poly` is fairly * straightforward. As in the `Function` example above, there is a struct with * a nested `Interface` class template and a nested `Members` alias template. * No macros are needed with C++17. * \par * Imagine we were defining something like a Java-style iterator. If we are * using a C++17 compiler, our interface would look something like this: * * template * struct IJavaIterator { * template * struct Interface : Base { * bool Done() const { return folly::poly_call<0>(*this); } * Value Current() const { return folly::poly_call<1>(*this); } * void Next() { folly::poly_call<2>(*this); } * }; * // NOTE: This works in C++17 only: * template * using Members = folly::PolyMembers<&T::Done, &T::Current, &T::Next>; * }; * * template * using JavaIterator = Poly; * * \par * Given the above definition, `JavaIterator` can be used to hold instances * of any type that has `Done`, `Current`, and `Next` member functions with the * correct (or compatible) signatures. * * \par * The presence of overloaded member functions complicates this picture. Often, * property members are faked in C++ with `const` and non-`const` member * function overloads, like in the interface specified below: * * struct IIntProperty { * template * struct Interface : Base { * int Value() const { return folly::poly_call<0>(*this); } * void Value(int i) { folly::poly_call<1>(*this, i); } * }; * // NOTE: This works in C++17 only: * template * using Members = folly::PolyMembers< * folly::sig(&T::Value), * folly::sig(&T::Value)>; * }; * * using IntProperty = Poly; * * \par * Now, any object that has `Value` members of compatible signatures can be * assigned to instances of `IntProperty` object. Note how `folly::sig` is used * to disambiguate the overloads of `&T::Value`. * * \par Defining an interface with C++14 * * \par * In C++14, the nice syntax above doesn't work, so we have to resort to macros. * The two examples above would look like this: * * template * struct IJavaIterator { * template * struct Interface : Base { * bool Done() const { return folly::poly_call<0>(*this); } * Value Current() const { return folly::poly_call<1>(*this); } * void Next() { folly::poly_call<2>(*this); } * }; * // NOTE: This works in C++14 and C++17: * template * using Members = FOLLY_POLY_MEMBERS(&T::Done, &T::Current, &T::Next); * }; * * template * using JavaIterator = Poly; * * \par * and * * struct IIntProperty { * template * struct Interface : Base { * int Value() const { return folly::poly_call<0>(*this); } * void Value(int i) { return folly::poly_call<1>(*this, i); } * }; * // NOTE: This works in C++14 and C++17: * template * using Members = FOLLY_POLY_MEMBERS( * FOLLY_POLY_MEMBER(int() const, &T::Value), * FOLLY_POLY_MEMBER(void(int), &T::Value)); * }; * * using IntProperty = Poly; * * \par Extending interfaces * * \par * One typical advantage of inheritance-based solutions to runtime polymorphism * is that one polymorphic interface could extend another through inheritance. * The same can be accomplished with type-erasing polymorphic wrappers. In * the `Poly` library, you can use `folly::PolyExtends` to say that one * interface extends another. * * struct IFoo { * template * struct Interface : Base { * void Foo() const { return folly::poly_call<0>(*this); } * }; * template * using Members = FOLLY_POLY_MEMBERS(&T::Foo); * }; * * // The IFooBar interface extends the IFoo interface * struct IFooBar : PolyExtends { * template * struct Interface : Base { * void Bar() const { return folly::poly_call<0>(*this); } * }; * template * using Members = FOLLY_POLY_MEMBERS(&T::Bar); * }; * * using FooBar = Poly; * * \par * Given the above defintion, instances of type `FooBar` have both `Foo()` and * `Bar()` member functions. * * \par * The sensible conversions exist between a wrapped derived type and a wrapped * base type. For instance, assuming `IDerived` extends `IBase` with * `PolyExtends`: * * Poly derived = ...; * Poly base = derived; // This conversion is OK. * * \par * As you would expect, there is no conversion in the other direction, and at * present there is no `Poly` equivalent to `dynamic_cast`. * * \par Type-erasing polymorphic reference wrappers * * \par * Sometimes you don't need to own a copy of an object; a reference will do. For * that you can use `Poly` to capture a _reference_ to an object satisfying an * interface rather than the whole object itself. The syntax is intuitive. * * int i = 42; * // Capture a mutable reference to an object of any IRegular type: * Poly intRef = i; * assert(42 == folly::poly_cast(intRef)); * // Assert that we captured the address of "i": * assert(&i == &folly::poly_cast(intRef)); * * \par * A reference-like `Poly` has a different interface than a value-like `Poly`. * Rather than calling member functions with the `obj.fun()` syntax, you would * use the `obj->fun()` syntax. This is for the sake of `const`-correctness. * For example, consider the code below: * * struct IFoo { * template * struct Interface { * void Foo() { folly::poly_call<0>(*this); } * }; * template * using Members = folly::PolyMembers<&T::Foo>; * }; * * struct SomeFoo { * void Foo() { std::printf("SomeFoo::Foo\n"); } * }; * * SomeFoo foo; * Poly const anyFoo = foo; * anyFoo->Foo(); // prints "SomeFoo::Foo" * * \par * Notice in the above code that the `Foo` member function is non-`const`. * Notice also that the `anyFoo` object is `const`. However, since it has * captured a non-`const` reference to the `foo` object, it should still be * possible to dispatch to the non-`const` `Foo` member function. When * instantiated with a reference type, `Poly` has an overloaded `operator->` * member that returns a pointer to the `IFoo` interface with the correct * `const`-ness, which makes this work. * * \par * The same mechanism also prevents users from calling non-`const` member * functions on `Poly` objects that have captured `const` references, which * would violate `const`-correctness. * * \par * Sensible conversions exist between non-reference and reference `Poly`s. For * instance: * * Poly value = 42; * Poly mutable_ref = value; * Poly const_ref = mutable_ref; * * assert(&poly_cast(value) == &poly_cast(mutable_ref)); * assert(&poly_cast(value) == &poly_cast(const_ref)); * * \par Non-member functions (C++17) * * \par * If you wanted to write the interface `ILogicallyNegatable`, which captures * all types that can be negated with unary `operator!`, you could do it * as we've shown above, by binding `&T::operator!` in the nested `Members` * alias template, but that has the problem that it won't work for types that * have defined unary `operator!` as a free function. To handle this case, * the `Poly` library lets you use a free function instead of a member function * when creating a binding. * * \par * With C++17 you may use a lambda to create a binding, as shown in the example * below: * * struct ILogicallyNegatable { * template * struct Interface : Base { * bool operator!() const { return folly::poly_call<0>(*this); } * }; * template * using Members = folly::PolyMembers< * +[](T const& t) -> decltype(!t) { return !t; }>; * }; * * \par * This requires some explanation. The unary `operator+` in front of the lambda * is necessary! It causes the lambda to decay to a C-style function pointer, * which is one of the types that `folly::PolyMembers` accepts. The `decltype` * in the lambda return type is also necessary. Through the magic of SFINAE, it * will cause `Poly` to reject any types that don't support * unary `operator!`. * * \par * If you are using a free function to create a binding, the first parameter is * implicitly the `this` parameter. It will receive the type-erased object. * * \par Non-member functions (C++14) * * \par * If you are using a C++14 compiler, the defintion of `ILogicallyNegatable` * above will fail because lambdas are not `constexpr`. We can get the same * effect by writing the lambda as a named free function, as show below: * * struct ILogicallyNegatable { * template * struct Interface : Base { * bool operator!() const { return folly::poly_call<0>(*this); } * }; * * template * static auto negate(T const& t) -> decltype(!t) { return !t; } * * template * using Members = FOLLY_POLY_MEMBERS(&negate); * }; * * \par * As with the example that uses the lambda in the preceding section, the first * parameter is implicitly the `this` parameter. It will receive the type-erased * object. * * \par Multi-dispatch * * \par * What if you want to create an `IAddable` interface for things that can be * added? Adding requires _two_ objects, both of which are type-erased. This * interface requires dispatching on both objects, doing the addition only * if the types are the same. For this we make use of the `PolySelf` template * alias to define an interface that takes more than one object of the the * erased type. * * struct IAddable { * template * struct Interface : Base { * friend PolySelf * operator+(PolySelf const& a, PolySelf const& b) { * return folly::poly_call<0, IAddable>(a, b); * } * }; * * template * using Members = folly::PolyMembers< * +[](T const& a, T const& b) -> decltype(a + b) { return a + b; }>; * }; * * \par * Given the above defintion of `IAddable` we would be able to do the following: * * Poly a = 2, b = 3; * Poly c = a + b; * assert(poly_cast(c) == 5); * * \par * If `a` and `b` stored objects of different types, a `BadPolyCast` exception * would be thrown. * * \par Move-only types * * \par * If you want to store move-only types, then your interface should extend the * `IMoveOnly` interface. * * \par Implementation notes * \par * `Poly` will store "small" objects in an internal buffer, avoiding the cost of * of dynamic allocations. At present, this size is not configurable; it is * pegged at the size of two `double`s. * * \par * `Poly` objects are always nothrow movable. If you store an object in one that * has a potentially throwing move contructor, the object will be stored on the * heap, even if it could fit in the internal storage of the `Poly` object. * (So be sure to give your objects nothrow move constructors!) * * \par * `Poly` implements type-erasure in a manner very similar to how the compiler * accomplishes virtual dispatch. Every `Poly` object contains a pointer to a * table of function pointers. Member function calls involve a double- * indirection: once through the v-pointer, and other indirect function call * through the function pointer. */ template struct Poly final : detail::PolyValOrRef { friend detail::PolyAccess; Poly() = default; using detail::PolyValOrRef::PolyValOrRef; using detail::PolyValOrRef::operator=; }; /** * Swap two `Poly` instances. */ template void swap(Poly& left, Poly& right) noexcept { left.swap(right); } /** * Pseudo-function template handy for disambiguating function overloads. * * For example, given: * struct S { * int property() const; * void property(int); * }; * * You can get a member function pointer to the first overload with: * folly::sig(&S::property); * * This is arguably a nicer syntax that using the built-in `static_cast`: * static_cast(&S::property); * * `sig` is also more permissive than `static_cast` about `const`. For instance, * the following also works: * folly::sig(&S::property); * * The above is permitted */ template FOLLY_INLINE_CONSTEXPR detail::Sig const sig = {}; } // namespace folly #include #undef FOLLY_INLINE_CONSTEXPR