1 // PR c++/82218
2 // { dg-do compile { target c++14 } }
3 // { dg-options "-fdelete-null-pointer-checks" }
4 
5 template<typename _Tp>
6 struct identity
7 {
8   typedef _Tp type;
9 };
10 
11 template<typename _Tp>
12 inline _Tp&&
forward(typename identity<_Tp>::type && __t)13 forward(typename identity<_Tp>::type&& __t)
14 { return __t; }
15 
16 template < typename T >
17 class delegate;
18 
19 template < typename R, typename... Params >
20 class delegate< R(Params...) > final
21 {
22 private:
23   using CallbackType = R (*)(void*, Params...);
24 
25   using FunctionPtr = R (*)(Params...);
26 
27   template < typename Object >
28   using MethodPtr = R (Object::*)(Params...);
29 
30   template < typename Object >
31   using ConstMethodPtr = R (Object::*)(Params...) const;
32 
33   void* obj_;
34   CallbackType cb_;
35 
36   template < typename Object, MethodPtr< Object > Mptr >
invoke_method(void * obj,Params...params)37   constexpr static R invoke_method(void* obj, Params... params) noexcept(
38       noexcept((static_cast< Object* >(obj)->*Mptr)(params...)))
39   {
40     return (static_cast< Object* >(obj)->*Mptr)(params...);
41   }
42 
43   template < typename Object, ConstMethodPtr< Object > Mptr >
invoke_method(void * obj,Params...params)44   constexpr static R invoke_method(void* obj, Params... params) noexcept(
45       noexcept((static_cast< Object* >(obj)->*Mptr)(params...)))
46   {
47     return (static_cast< Object* >(obj)->*Mptr)(params...);
48   }
49 
50   template < FunctionPtr Fptr >
invoke_function(void *,Params...params)51   constexpr static R invoke_function(void*, Params... params) noexcept(
52       noexcept((*Fptr)(params...)))
53   {
54     return (*Fptr)(params...);
55   }
56 
delegate(void * obj,CallbackType callback)57   constexpr delegate(void* obj, CallbackType callback) noexcept : obj_(obj),
58                                                                   cb_(callback)
59   {
60   }
61 
error_function(Params...)62   constexpr static R error_function(Params...)
63   {
64     while(1);
65   }
66 
67 public:
68   using base_type = delegate< R(Params...) >;
69 
delegate()70   delegate()
71   {
72     *this = from< error_function >();
73   }
74 
75   delegate(const base_type&) = default;
76   delegate(base_type&&)      = default;
77 
78   base_type& operator=(const base_type&)  = default;
79   base_type& operator=(base_type&&)       = default;
80 
81   template < typename Object, MethodPtr< Object > Mptr >
from(Object & obj)82   constexpr static auto from(Object& obj) noexcept
83   {
84     return delegate(&obj, &invoke_method< Object, Mptr >);
85   }
86 
87   template < typename Object, ConstMethodPtr< Object > Mptr >
from(Object & obj)88   constexpr static auto from(Object& obj) noexcept
89   {
90     return delegate(&obj, &invoke_method< Object, Mptr >);
91   }
92 
93   template < FunctionPtr Fptr >
from()94   constexpr static auto from() noexcept
95   {
96     static_assert(Fptr != nullptr, "Function pointer must not be null");
97 
98     return delegate(nullptr, &invoke_function< Fptr >);
99   }
100 
101   template < typename... Args >
operator()102   constexpr auto operator()(Args&&... params) const
103       noexcept(noexcept((*cb_)(obj_, forward< Args >(params)...)))
104   {
105     return (*cb_)(obj_, forward< Args >(params)...);
106   }
107 
valid()108   constexpr bool valid() const noexcept
109   {
110     return (cb_ != &invoke_function< error_function >);
111   }
112 
113   constexpr bool operator==(const delegate& other) const noexcept
114   {
115     return (obj_ == other.obj_) && (cb_ == other.cb_);
116   }
117 
118   constexpr bool operator!=(const delegate& other) const noexcept
119   {
120     return (obj_ != other.obj_) || (cb_ != other.cb_);
121   }
122 };
123 
124 delegate< void(void) > a;
125 
test()126 void test()
127 {
128   a();
129 }
130