2 * Copyright 2017-present Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
22 #include <type_traits>
26 #include <folly/Traits.h>
27 #include <folly/Utility.h>
28 #include <folly/detail/TypeList.h>
29 #include <folly/functional/Invoke.h>
37 using RRef_ = MetaQuoteTrait<std::add_rvalue_reference>;
38 using LRef_ = MetaQuoteTrait<std::add_lvalue_reference>;
41 struct XRef_ : Type<MetaQuoteTrait<Type>> {};
43 using XRef = _t<XRef_<T>>;
45 struct XRef_<T&&> : Type<MetaCompose<RRef_, XRef<T>>> {};
47 struct XRef_<T&> : Type<MetaCompose<LRef_, XRef<T>>> {};
49 struct XRef_<T const> : Type<MetaQuoteTrait<std::add_const>> {};
51 template <class A, class B>
52 using AddCvrefOf = MetaApply<XRef<B>, A>;
59 template <class T, class I>
60 detail::AddCvrefOf<T, I>& poly_cast(detail::PolyRoot<I>&);
62 template <class T, class I>
63 detail::AddCvrefOf<T, I> const& poly_cast(detail::PolyRoot<I> const&);
65 #if !defined(__cpp_template_auto)
66 #define FOLLY_AUTO class
67 template <class... Ts>
68 using PolyMembers = detail::TypeList<Ts...>;
70 #define FOLLY_AUTO auto
77 /* *****************************************************************************
78 * IMPLEMENTATION NOTES
81 Building the Interface
82 ----------------------
84 Here is a high-level description of how Poly works. Users write an interface
91 return folly::poly_call<0>(*this);
95 using Members = folly::PolyMembers<&T::Exec>;
98 Then they instantiate Poly<Mine>, which will have an Exec member function
99 of the correct signature. The Exec member function comes from
100 Mine::Interface<PolyNode<Mine, PolyRoot<Mine>>>, from which Poly<Mine> inherits.
101 Here's what each piece means:
103 - PolyRoot<I>: stores Data, which is a union of a void* (used when the Poly is
104 storing an object on the heap or a reference) and some aligned storage (used
105 when the Poly is storing an object in-situ). PolyRoot also stores a vtable
106 pointer for interface I, which is a pointer to a struct containing function
107 pointers. The function pointers are bound member functions (e.g.,
108 SomeType::Exec). More on the vtable pointer and how it is generated below.
110 - PolyNode: provides the hooks used by folly::poly_call to dispatch to the
111 correctly bound member function for this interface. In the context of an
112 interface I, folly::poly_call<K>(*this, args...) will:
113 1. Fetch the vtable pointer from PolyRoot,
114 2. Select the I portion of that vtable (which, in the case of interface
115 extension, may only be a part of the total vtable),
116 3. Fetch the K-th function pointer from that vtable part,
117 4. Call through that function pointer, passing Data (from PolyRoot) and any
118 additional arguments in the folly::poly_call<K> invocation.
120 In the case of interface extension -- for instance, if interface Mine extended
121 interface Yours by inheriting from PolyExtends<Yours> -- then interface Mine
122 will have a list of base interfaces in a typelist called "Subsumptions".
123 Poly<Mine> will fold all the subsumed interfaces together, linearly inheriting
124 from them. To take the example of an interface Mine that extends Yours,
125 Poly<Mine> would inherit from this type:
130 PolyNode<Your, PolyRoot<Mine>>>>>
132 Through linear inheritance, Poly<Mine> ends up with the public member functions
133 of both interfaces, Mine and Yours.
138 As mentioned above, PolyRoot<I> stores a vtable pointer for interface I. The
139 vtable is a struct whose members are function pointers. How are the types of
140 those function pointers computed from the interface? A dummy type is created,
141 Archetype<I>, in much the same way that Poly<I>'s base type is computed. Instead
142 of PolyNode and PolyRoot, there is ArchetypeNode and ArchetypeRoot. These types
143 also provide hooks for folly::poly_call, but they are dummy hooks that do
144 nothing. (Actually, they call std::terminate; they will never be called.) Once
145 Archetype<I> has been constructed, it is a concrete type that has all the
146 member functions of the interface and its subsumed interfaces. That type is
147 passed to Mine::Members, which takes the address of Archetype<I>::Exec and
148 inspects the resulting member function type. This is done for each member in the
149 interface. From a list of [member] function pointers, it is a simple matter of
150 metaprogramming to build a struct of function pointers. std::tuple is used for
153 An extra field is added to the tuple for a function that handles all of the
154 "special" operations: destruction, copying, moving, getting the type
155 information, getting the address of the stored object, and fetching a fixed-up
156 vtable pointer for reference conversions (e.g., I -> I&, I& -> I const&, etc).
158 Subsumed interfaces are handled by having VTable<IDerived> inherit from
159 BasePtr<IBase>, where BasePtr<IBase> has only one member of type
160 VTable<IBase> const*.
162 Now that the type of VTable<I> is computed, how are the fields populated?
163 Poly<I> default-constructs to an empty state. Its vtable pointer points to a
164 vtable whose fields are initialized with the addresses of functions that do
165 nothing but throw a BadPolyAccess exception. That way, if you call a member
166 function on an empty Poly, you get an exception. The function pointer
167 corresponding to the "special" operations points to a no-op function; copying,
168 moving and destroying an empty Poly does nothing.
170 On the other hand, when you pass an object of type T satisfying interface I to
171 Poly<I>'s constructor or assignment operator, a vtable for {I,T} is reified by
172 passing type T to I::Members, thereby creating a list of bindings for T's member
173 functions. The address of this vtable gets stored in the PolyRoot<I> subobject,
174 imbuing the Poly object with the behaviors of type T. The T object itself gets
175 stored either on the heap or in the aligned storage within the Poly object
176 itself, depending on the size of T and whether or not it has a noexcept move
181 using Uncvref = std::remove_cv_t<std::remove_reference_t<T>>;
183 template <class T, template <class...> class U>
184 struct IsInstanceOf : std::false_type {};
186 template <class... Ts, template <class...> class U>
187 struct IsInstanceOf<U<Ts...>, U> : std::true_type {};
190 using Not = Bool<!T::value>;
194 static constexpr T value{};
198 constexpr T StaticConst<T>::value;
201 void if_constexpr(std::true_type, Fun fun) {
206 void if_constexpr(std::false_type, Fun) {}
208 enum class Op : short { eNuke, eMove, eCopy, eType, eAddr, eRefr };
210 enum class RefType : std::uintptr_t { eRvalue, eLvalue, eConstLvalue };
223 using IsPoly = IsInstanceOf<Uncvref<T>, Poly>;
225 // Given an interface I and a concrete type T that satisfies the interface
226 // I, create a list of member function bindings from members of T to members
228 template <class I, class T>
229 using MembersOf = typename I::template Members<Uncvref<T>>;
231 // Given an interface I and a base type T, create a type that implements
232 // the interface I in terms of the capabilities of T.
233 template <class I, class T>
234 using InterfaceOf = typename I::template Interface<T>;
236 [[noreturn]] void throwBadPolyAccess();
237 [[noreturn]] void throwBadPolyCast();
239 #if !defined(__cpp_template_auto)
240 template <class T, T V>
241 using Member = std::integral_constant<T, V>;
244 using MemberType = typename M::value_type;
247 inline constexpr MemberType<M> memberValue() noexcept {
251 template <class... Ts>
254 using Members = PolyMembers<Member<Ts, Vs>...>;
257 template <class... Ts>
258 MakeMembers<Ts...> deduceMembers(Ts...);
260 template <class Member, class = MemberType<Member>>
263 template <class Member, class R, class D, class... As>
264 struct MemberDef<Member, R (D::*)(As...)> {
265 static R value(D& d, As... as) {
266 return folly::invoke(memberValue<Member>(), d, static_cast<As&&>(as)...);
270 template <class Member, class R, class D, class... As>
271 struct MemberDef<Member, R (D::*)(As...) const> {
272 static R value(D const& d, As... as) {
273 return folly::invoke(memberValue<Member>(), d, static_cast<As&&>(as)...);
279 using MemberType = decltype(M);
282 inline constexpr MemberType<M> memberValue() noexcept {
289 template <class I, class = void>
290 struct SubsumptionsOf_ {
291 using type = TypeList<>;
295 using InclusiveSubsumptionsOf = TypePushFront<_t<SubsumptionsOf_<I>>, I>;
298 struct SubsumptionsOf_<I, void_t<typename I::Subsumptions>> {
299 using type = TypeJoin<TypeTransform<
300 typename I::Subsumptions,
301 MetaQuote<InclusiveSubsumptionsOf>>>;
305 using SubsumptionsOf = TypeReverseUnique<_t<SubsumptionsOf_<I>>>;
309 [[noreturn]] /* implicit */ operator T &&() const {
314 using ArchetypeNode = MetaQuote<InterfaceOf>;
317 struct ArchetypeRoot;
321 TypeFold<InclusiveSubsumptionsOf<I>, ArchetypeRoot<I>, ArchetypeNode>;
323 struct ArchetypeBase : Bottom {
324 ArchetypeBase() = default;
326 /* implicit */ ArchetypeBase(T&&);
327 template <std::size_t, class... As>
328 [[noreturn]] Bottom _polyCall_(As&&...) const { std::terminate(); }
330 friend bool operator==(ArchetypeBase const&, ArchetypeBase const&);
331 friend bool operator!=(ArchetypeBase const&, ArchetypeBase const&);
332 friend bool operator<(ArchetypeBase const&, ArchetypeBase const&);
333 friend bool operator<=(ArchetypeBase const&, ArchetypeBase const&);
334 friend bool operator>(ArchetypeBase const&, ArchetypeBase const&);
335 friend bool operator>=(ArchetypeBase const&, ArchetypeBase const&);
336 friend Bottom operator++(ArchetypeBase const&);
337 friend Bottom operator++(ArchetypeBase const&, int);
338 friend Bottom operator--(ArchetypeBase const&);
339 friend Bottom operator--(ArchetypeBase const&, int);
340 friend Bottom operator+(ArchetypeBase const&, ArchetypeBase const&);
341 friend Bottom operator+=(ArchetypeBase const&, ArchetypeBase const&);
342 friend Bottom operator-(ArchetypeBase const&, ArchetypeBase const&);
343 friend Bottom operator-=(ArchetypeBase const&, ArchetypeBase const&);
344 friend Bottom operator*(ArchetypeBase const&, ArchetypeBase const&);
345 friend Bottom operator*=(ArchetypeBase const&, ArchetypeBase const&);
346 friend Bottom operator/(ArchetypeBase const&, ArchetypeBase const&);
347 friend Bottom operator/=(ArchetypeBase const&, ArchetypeBase const&);
348 friend Bottom operator%(ArchetypeBase const&, ArchetypeBase const&);
349 friend Bottom operator%=(ArchetypeBase const&, ArchetypeBase const&);
350 friend Bottom operator<<(ArchetypeBase const&, ArchetypeBase const&);
351 friend Bottom operator<<=(ArchetypeBase const&, ArchetypeBase const&);
352 friend Bottom operator>>(ArchetypeBase const&, ArchetypeBase const&);
353 friend Bottom operator>>=(ArchetypeBase const&, ArchetypeBase const&);
357 struct ArchetypeRoot : ArchetypeBase {
358 template <class Node, class Tfx>
359 using _polySelf_ = Archetype<AddCvrefOf<MetaApply<Tfx, I>, Node>>;
360 using _polyInterface_ = I;
365 // Suppress compiler-generated copy ops to not copy anything:
367 Data& operator=(Data const&) {
371 void* pobj_ = nullptr;
372 std::aligned_storage_t<sizeof(double[2])> buff_;
376 template <class U, class I>
378 If<std::is_same<Uncvref<U>, Archetype<I>>::value,
379 Poly<AddCvrefOf<I, U const&>>,
382 template <class U, class I>
384 If<std::is_same<Uncvref<U>, Archetype<I>>::value,
385 AddCvrefOf<Poly<I>, U>,
388 template <class Member, class I>
391 template <class R, class C, class... As, class I>
392 struct SignatureOf_<R (C::*)(As...), I> {
393 using type = Ret<R, I> (*)(Data&, Arg<As, I>...);
396 template <class R, class C, class... As, class I>
397 struct SignatureOf_<R (C::*)(As...) const, I> {
398 using type = Ret<R, I> (*)(Data const&, Arg<As, I>...);
401 template <class R, class This, class... As, class I>
402 struct SignatureOf_<R (*)(This&, As...), I> {
403 using type = Ret<R, I> (*)(Data&, Arg<As, I>...);
406 template <class R, class This, class... As, class I>
407 struct SignatureOf_<R (*)(This const&, As...), I> {
408 using type = Ret<R, I> (*)(Data const&, Arg<As, I>...);
411 template <FOLLY_AUTO Arch, class I>
412 using SignatureOf = _t<SignatureOf_<MemberType<Arch>, I>>;
414 template <FOLLY_AUTO User, class I, class Sig = SignatureOf<User, I>>
417 template <FOLLY_AUTO User, class I, class Ret, class Data, class... Args>
418 struct ArgTypes_<User, I, Ret (*)(Data, Args...)> {
419 using type = TypeList<Args...>;
422 template <FOLLY_AUTO User, class I>
423 using ArgTypes = _t<ArgTypes_<User, I>>;
425 template <class R, class... Args>
426 using FnPtr = R (*)(Args...);
429 template <class R, class... Args>
430 constexpr /* implicit */ operator FnPtr<R, Args...>() const noexcept {
432 static R call(Args...) {
433 throwBadPolyAccess();
440 inline constexpr ThrowThunk throw_() noexcept {
445 inline constexpr bool inSitu() noexcept {
446 return !std::is_reference<T>::value &&
447 sizeof(std::decay_t<T>) <= sizeof(Data) &&
448 std::is_nothrow_move_constructible<std::decay_t<T>>::value;
452 T& get(Data& d) noexcept {
454 return *(std::add_pointer_t<T>)static_cast<void*>(&d.buff_);
456 return *static_cast<std::add_pointer_t<T>>(d.pobj_);
461 T const& get(Data const& d) noexcept {
463 return *(std::add_pointer_t<T const>)static_cast<void const*>(&d.buff_);
465 return *static_cast<std::add_pointer_t<T const>>(d.pobj_);
469 enum class State : short { eEmpty, eInSitu, eOnHeap };
471 template <class, class U>
472 U&& convert(U&& u) noexcept {
473 return static_cast<U&&>(u);
476 template <class Arg, class I>
477 decltype(auto) convert(Poly<I&> u) {
478 return poly_cast<Uncvref<Arg>>(u.get());
482 struct IsConstMember : std::false_type {};
484 template <class R, class C, class... As>
485 struct IsConstMember<R (C::*)(As...) const> : std::true_type {};
487 template <class R, class C, class... As>
488 struct IsConstMember<R (*)(C const&, As...)> : std::true_type {};
494 class = ArgTypes<User, I>,
497 template <class R, class D, class... As>
498 constexpr /* implicit */ operator FnPtr<R, D&, As...>() const noexcept {
503 template <class T, FOLLY_AUTO User, class I, class... Args>
510 !std::is_const<std::remove_reference_t<T>>::value ||
511 IsConstMember<MemberType<User>>::value>> {
512 template <class R, class D, class... As>
513 constexpr /* implicit */ operator FnPtr<R, D&, As...>() const noexcept {
515 static R call(D& d, As... as) {
516 return folly::invoke(
519 convert<Args>(static_cast<As&&>(as))...);
528 class = MembersOf<I, Archetype<I>>,
529 class = SubsumptionsOf<I>>
532 template <class T, FOLLY_AUTO User, class I>
533 inline constexpr ThunkFn<T, User, I> thunk() noexcept {
534 return ThunkFn<T, User, I>{};
538 constexpr VTable<I> const* vtable() noexcept {
539 return &StaticConst<VTable<I>>::value;
542 template <class I, class T>
543 struct VTableFor : VTable<I> {
544 constexpr VTableFor() noexcept : VTable<I>{Type<T>{}} {}
547 template <class I, class T>
548 constexpr VTable<I> const* vtableFor() noexcept {
549 return &StaticConst<VTableFor<I, T>>::value;
552 template <class I, class T>
553 constexpr void* vtableForRef(RefType ref) {
555 case RefType::eRvalue:
556 return const_cast<VTable<I>*>(vtableFor<I, T&&>());
557 case RefType::eLvalue:
558 return const_cast<VTable<I>*>(vtableFor<I, T&>());
559 case RefType::eConstLvalue:
560 return const_cast<VTable<I>*>(vtableFor<I, T const&>());
568 std::enable_if_t<std::is_reference<T>::value, int> = 0>
569 void* execOnHeap(Op op, Data* from, void* to) {
575 static_cast<Data*>(to)->pobj_ = from->pobj_;
578 return const_cast<void*>(static_cast<void const*>(&typeid(T)));
580 if (*static_cast<std::type_info const*>(to) == typeid(T)) {
585 return vtableForRef<I, Uncvref<T>>(
586 static_cast<RefType>(reinterpret_cast<std::uintptr_t>(to)));
594 std::enable_if_t<Not<std::is_reference<T>>::value, int> = 0>
595 void* execOnHeap(Op op, Data* from, void* to) {
598 delete &get<T>(*from);
601 static_cast<Data*>(to)->pobj_ = std::exchange(from->pobj_, nullptr);
604 detail::if_constexpr(std::is_copy_constructible<T>(), [&](auto id) {
605 static_cast<Data*>(to)->pobj_ = new T(id(get<T>(*from)));
609 return const_cast<void*>(static_cast<void const*>(&typeid(T)));
611 if (*static_cast<std::type_info const*>(to) == typeid(T)) {
616 return vtableForRef<I, Uncvref<T>>(
617 static_cast<RefType>(reinterpret_cast<std::uintptr_t>(to)));
622 template <class I, class T>
623 void* execInSitu(Op op, Data* from, void* to) {
629 ::new (static_cast<void*>(&static_cast<Data*>(to)->buff_))
630 T(std::move(get<T>(*from)));
634 detail::if_constexpr(std::is_copy_constructible<T>(), [&](auto id) {
635 ::new (static_cast<void*>(&static_cast<Data*>(to)->buff_))
636 T(id(get<T>(*from)));
640 return const_cast<void*>(static_cast<void const*>(&typeid(T)));
642 if (*static_cast<std::type_info const*>(to) == typeid(T)) {
647 return vtableForRef<I, Uncvref<T>>(
648 static_cast<RefType>(reinterpret_cast<std::uintptr_t>(to)));
653 inline void* noopExec(Op op, Data*, void*) {
655 throwBadPolyAccess();
656 return const_cast<void*>(static_cast<void const*>(&typeid(void)));
661 VTable<I> const* vptr_;
664 template <class I, class T, std::enable_if_t<inSitu<T>(), int> = 0>
665 constexpr void* (*getOps() noexcept)(Op, Data*, void*) {
666 return &execInSitu<I, T>;
669 template <class I, class T, std::enable_if_t<!inSitu<T>(), int> = 0>
670 constexpr void* (*getOps() noexcept)(Op, Data*, void*) {
671 return &execOnHeap<I, T>;
674 template <class I, FOLLY_AUTO... Arch, class... S>
675 struct VTable<I, PolyMembers<Arch...>, TypeList<S...>>
676 : BasePtr<S>..., std::tuple<SignatureOf<Arch, I>...> {
678 template <class T, FOLLY_AUTO... User>
679 constexpr VTable(Type<T>, PolyMembers<User...>) noexcept
680 : BasePtr<S>{vtableFor<S, T>()}...,
681 std::tuple<SignatureOf<Arch, I>...>{thunk<T, User, I>()...},
682 state_{inSitu<T>() ? State::eInSitu : State::eOnHeap},
683 ops_{getOps<I, T>()} {}
686 constexpr VTable() noexcept
687 : BasePtr<S>{vtable<S>()}...,
688 std::tuple<SignatureOf<Arch, I>...>{
689 static_cast<SignatureOf<Arch, I>>(throw_())...},
690 state_{State::eEmpty},
694 explicit constexpr VTable(Type<T>) noexcept
695 : VTable{Type<T>{}, MembersOf<I, T>{}} {}
698 void* (*ops_)(Op, Data*, void*);
702 constexpr VTable<I> const& select(VTable<_t<Type<I>>> const& vtbl) noexcept {
707 constexpr VTable<I> const& select(BasePtr<_t<Type<I>>> const& base) noexcept {
712 template <std::size_t N, typename This, typename... As>
713 static auto call(This&& _this, As&&... args)
714 -> decltype(static_cast<This&&>(_this).template _polyCall_<N>(
715 static_cast<As&&>(args)...)) {
717 !IsInstanceOf<std::decay_t<This>, Poly>::value,
718 "When passing a Poly<> object to call(), you must explicitly "
719 "say which Interface to dispatch to, as in "
720 "call<0, MyInterface>(self, args...)");
721 return static_cast<This&&>(_this).template _polyCall_<N>(
722 static_cast<As&&>(args)...);
725 template <class Poly>
726 using Iface = typename Uncvref<Poly>::_polyInterface_;
728 template <class Node, class Tfx = MetaIdentity>
729 static typename Uncvref<Node>::template _polySelf_<Node, Tfx> self_();
731 template <class T, class Poly, class I = Iface<Poly>>
732 static decltype(auto) cast(Poly&& _this) {
733 using Ret = AddCvrefOf<AddCvrefOf<T, I>, Poly&&>;
734 return static_cast<Ret>(
735 *static_cast<std::add_pointer_t<Ret>>(_this.vptr_->ops_(
737 const_cast<Data*>(static_cast<Data const*>(&_this)),
738 const_cast<void*>(static_cast<void const*>(&typeid(T))))));
741 template <class Poly>
742 static decltype(auto) root(Poly&& _this) noexcept {
743 return static_cast<Poly&&>(_this)._polyRoot_();
747 static std::type_info const& type(PolyRoot<I> const& _this) noexcept {
748 return *static_cast<std::type_info const*>(
749 _this.vptr_->ops_(Op::eType, nullptr, nullptr));
753 static VTable<Uncvref<I>> const* vtable(PolyRoot<I> const& _this) noexcept {
758 static Data* data(PolyRoot<I>& _this) noexcept {
763 static Data const* data(PolyRoot<I> const& _this) noexcept {
768 static Poly<I&&> move(PolyRoot<I&> const& _this) noexcept {
769 return Poly<I&&>{_this, Type<I&>{}};
773 static Poly<I const&> move(PolyRoot<I const&> const& _this) noexcept {
774 return Poly<I const&>{_this, Type<I const&>{}};
778 template <class I, class Tail>
779 struct PolyNode : Tail {
784 template <std::size_t K, typename... As>
785 decltype(auto) _polyCall_(As&&... as) {
786 return std::get<K>(select<I>(*PolyAccess::vtable(*this)))(
787 *PolyAccess::data(*this), static_cast<As&&>(as)...);
789 template <std::size_t K, typename... As>
790 decltype(auto) _polyCall_(As&&... as) const {
791 return std::get<K>(select<I>(*PolyAccess::vtable(*this)))(
792 *PolyAccess::data(*this), static_cast<As&&>(as)...);
796 struct MakePolyNode {
797 template <class I, class State>
798 using apply = InterfaceOf<I, PolyNode<I, State>>;
802 struct PolyRoot : private PolyBase, private Data {
807 template <class Node, class Tfx>
808 using _polySelf_ = Poly<AddCvrefOf<MetaApply<Tfx, I>, Node>>;
809 using _polyInterface_ = I;
812 PolyRoot& _polyRoot_() noexcept {
815 PolyRoot const& _polyRoot_() const noexcept {
818 VTable<std::decay_t<I>> const* vptr_ = vtable<std::decay_t<I>>();
823 TypeFold<InclusiveSubsumptionsOf<Uncvref<I>>, PolyRoot<I>, MakePolyNode>;
825 // A const-qualified function type means the user is trying to disambiguate
826 // a member function pointer.
827 template <class Fun> // Fun = R(As...) const
830 constexpr Fun T::*operator()(Fun T::*t) const /* nolint */ volatile noexcept {
833 template <class F, class T>
834 constexpr F T::*operator()(F T::*t) const /* nolint */ volatile noexcept {
839 // A functon type with no arguments means the user is trying to disambiguate
840 // a member function pointer.
842 struct Sig<R()> : Sig<R() const> {
844 using Sig<R() const>::operator();
847 constexpr Fun T::*operator()(Fun T::*t) const noexcept {
852 template <class R, class... As>
853 struct SigImpl : Sig<R(As...) const> {
854 using Fun = R(As...);
855 using Sig<R(As...) const>::operator();
858 constexpr Fun T::*operator()(Fun T::*t) const noexcept {
861 constexpr Fun* operator()(Fun* t) const noexcept {
865 constexpr F* operator()(F* t) const noexcept {
870 // The user could be trying to disambiguate either a member or a free function.
871 template <class R, class... As>
872 struct Sig<R(As...)> : SigImpl<R, As...> {};
874 // This case is like the one above, except we want to add an overload that
875 // handles the case of a free function where the first argument is more
876 // const-qualified than the user explicitly specified.
877 template <class R, class A, class... As>
878 struct Sig<R(A&, As...)> : SigImpl<R, A&, As...> {
879 using CCFun = R(A const&, As...);
880 using SigImpl<R, A&, As...>::operator();
882 constexpr CCFun* operator()(CCFun* t) const /* nolint */ volatile noexcept {
890 class U = std::decay_t<T>,
891 std::enable_if_t<Not<std::is_base_of<PolyBase, U>>::value, int> = 0,
892 std::enable_if_t<std::is_constructible<AddCvrefOf<U, I>, T>::value, int> =
894 class = MembersOf<std::decay_t<I>, U>>
895 std::true_type modelsInterface_(int);
896 template <class T, class I>
897 std::false_type modelsInterface_(long);
899 template <class T, class I>
900 struct ModelsInterface : decltype(modelsInterface_<T, I>(0)) {};
902 template <class I1, class I2>
903 struct ValueCompatible : std::is_base_of<I1, I2> {};
905 // This prevents PolyRef's converting constructors and assignment operators
906 // from being considered as copy constructors and assignment operators:
908 struct ValueCompatible<I1, I1> : std::false_type {};
910 template <class I1, class I2, class I2Ref>
911 struct ReferenceCompatible : std::is_constructible<I1, I2Ref> {};
913 // This prevents PolyRef's converting constructors and assignment operators
914 // from being considered as copy constructors and assignment operators:
915 template <class I1, class I2Ref>
916 struct ReferenceCompatible<I1, I1, I2Ref> : std::false_type {};
918 } // namespace detail