C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Chimeric Pointer

From: Marcin Jaczewski <marcinjaczewski86_at_[hidden]>
Date: Fri, 2 Dec 2022 10:26:11 +0100
czw., 1 gru 2022 o 16:29 Frederick Virchanza Gotham via Std-Proposals
<std-proposals_at_[hidden]> napisaƂ(a):
>
> On Thu, Dec 1, 2022 at 10:48 AM Frederick Virchanza Gotham
> <cauldwell.thomas_at_[hidden]> wrote:
> >
> > Today I've gotten a little closer to implementing some kind of
> > chimeric pointer (although for now it's a chimeric reference, but that
> > can change in the future).
>
> I've made more progress using the C/C++ preprocessor to aid in the creation of
> a chimeric reference type. In order to create the new type that you
> need, you write
> three lines in your header/source file as follows:
>
> #define CHIMERIC_TYPE ControlWithTextEntry
> DEFINE_CHIMERIC_TYPE_METHODS(SetBackgroundColour,SetValue,Refresh)
> DEFINE_CHIMERIC_TYPE_BASES (Control,TextEntry)
>
> The first line is what you want to call the new type.
> The second line is a list of all the member functions you need to use.
> The third line is a list of all the bases classes you need to use.
>
> Note that you don't need to specify which Base class contains which
> member function
> -- that part is figured out for you automagically. Then you can just
> use the new type as
> follows:
>
> void Red( chimeric_ref_ControlWithTextEntry arg )
> {
> arg.SetBackgroundColour("red");
> arg.SetValue("pending");
> arg.Refresh();
> }
>
> I have a working code example up on GodBolt:
>
> https://godbolt.org/z/zYK4aqssq
>
> And also I have copy-pasted all the code from Godbolt here:
>
> #include <iostream>
> using std::cout;
> using std::endl;
>
> // ================= Section 1: Example classes to play around with
>
> struct Control {
> virtual ~Control(void) = default;
>
> void SetBackgroundColour(const char*) { cout << "Invocation of
> Control::SetBackgroundColour\n"; }
> void Refresh (void ) { cout << "Invocation of
> Control::Refresh\n" ; }
> };
>
> struct TextEntry {
> virtual ~TextEntry(void) = default;
>
> void SetValue(const char*) { cout << "Invocation of
> TextEntry::SetValue\n"; }
> };
>
> struct TextControl : Control, TextEntry {
> virtual ~TextControl(void) = default;
> };
>
> struct Combo : Control, TextEntry {
> virtual ~Combo(void) = default;
> };
>
> // ================= Section 2: Preprocessor macro to implement any
> member function of any name
>
> #define IMPLEMENT_METHOD(Method)
> \
> template<typename... Types>
> \
> auto Method(Types... a)
> \
> {
> \
> using std::get;
> \
>
> \
> decltype(pointers) &p = pointers;
> \
>
> \
> if constexpr(requires{get< 0>(p)->Method(a...); })return get<
> 0>(p)->Method(a...);\
> else if constexpr(requires{get< 1>(p)->Method(a...); })return get<
> 1>(p)->Method(a...);\
> else if constexpr(requires{get< 2>(p)->Method(a...); })return get<
> 2>(p)->Method(a...);\
> else if constexpr(requires{get< 3>(p)->Method(a...); })return get<
> 3>(p)->Method(a...);\
> else if constexpr(requires{get< 4>(p)->Method(a...); })return get<
> 4>(p)->Method(a...);\
> else if constexpr(requires{get< 5>(p)->Method(a...); })return get<
> 5>(p)->Method(a...);\
> else if constexpr(requires{get< 6>(p)->Method(a...); })return get<
> 6>(p)->Method(a...);\
> else if constexpr(requires{get< 7>(p)->Method(a...); })return get<
> 7>(p)->Method(a...);\
> else if constexpr(requires{get< 8>(p)->Method(a...); })return get<
> 8>(p)->Method(a...);\
> else if constexpr(requires{get< 9>(p)->Method(a...); })return get<
> 9>(p)->Method(a...);\
> else if constexpr(requires{get<10>(p)->Method(a...); })return
> get<10>(p)->Method(a...);\
> else if constexpr(requires{get<11>(p)->Method(a...); })return
> get<11>(p)->Method(a...);\
> else if constexpr(requires{get<12>(p)->Method(a...); })return
> get<12>(p)->Method(a...);\
> else if constexpr(requires{get<13>(p)->Method(a...); })return
> get<13>(p)->Method(a...);\
> else if constexpr(requires{get<14>(p)->Method(a...); })return
> get<14>(p)->Method(a...);\
> else if constexpr(requires{get<15>(p)->Method(a...); })return
> get<15>(p)->Method(a...);\
> }
>
> // ================= Section 3: Implementation of chimeric_ref
>
> #include <tuple> // tuple, get
> #include <type_traits> // is_convertible_v
>
> #define M_NARGS(...) M_NARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
> #define M_NARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
>
> #define M_CONC(A, B) M_CONC_(A, B)
> #define M_CONC_(A, B) A##B
>
> #define M_FOR_EACH(ACTN, ...) M_CONC(M_FOR_EACH_,
> M_NARGS(__VA_ARGS__)) (ACTN, __VA_ARGS__)
>
> #define M_FOR_EACH_0(ACTN, E) E
> #define M_FOR_EACH_1(ACTN, E) ACTN(E)
> #define M_FOR_EACH_2(ACTN, E, ...) ACTN(E) M_FOR_EACH_1(ACTN, __VA_ARGS__)
> #define M_FOR_EACH_3(ACTN, E, ...) ACTN(E) M_FOR_EACH_2(ACTN, __VA_ARGS__)
> #define M_FOR_EACH_4(ACTN, E, ...) ACTN(E) M_FOR_EACH_3(ACTN, __VA_ARGS__)
> #define M_FOR_EACH_5(ACTN, E, ...) ACTN(E) M_FOR_EACH_4(ACTN, __VA_ARGS__)
>
> #define TOKENCAT_DETAIL(x, y) x ## y
> #define TOKENCAT(x, y) TOKENCAT_DETAIL(x, y)
>
> #define DEFINE_CHIMERIC_TYPE_METHODS(...) \
> template<class... Bases> \
> class TOKENCAT(chimeric_ref_detail_,CHIMERIC_TYPE) { \
> protected: \
> \
> std::tuple<Bases*...> pointers; \
> \
> public: \
> \
> template<class T> \
> requires ((std::is_convertible_v<T*, Bases*> && ...)) \
> /* implicit */ TOKENCAT(chimeric_ref_detail_,CHIMERIC_TYPE)(T &obj) \
> { \
> /* The fold expression on the next line sets */ \
> /* each of the pointers in the tuple */ \
> ((std::get<Bases*>(pointers) = &obj), ...); \
> } \
> \
> M_FOR_EACH(IMPLEMENT_METHOD, __VA_ARGS__) \
> };
>
> #define DEFINE_CHIMERIC_TYPE_BASES(...) typedef
> TOKENCAT(chimeric_ref_detail_,CHIMERIC_TYPE) < __VA_ARGS__ >
> TOKENCAT(chimeric_ref_,CHIMERIC_TYPE);
>
> // ================= Section 4: Test Code
>
> #define CHIMERIC_TYPE ControlWithTextEntry
> DEFINE_CHIMERIC_TYPE_METHODS(SetBackgroundColour,SetValue,Refresh)
> DEFINE_CHIMERIC_TYPE_BASES (Control,TextEntry)
>
> void Red( chimeric_ref_ControlWithTextEntry arg )
> {
> arg.SetBackgroundColour("red");
> arg.SetValue("pending");
> arg.Refresh();
> }
>
> void UseRed(TextControl &textCtrl, Combo &combo)
> {
> Red(textCtrl);
> Red(combo);
> }
>
> int main(void)
> {
> TextControl t;
> Combo c;
>
> UseRed(t,c);
> }
>
> // A little more test code:
>
> #include <string>
> #include <vector>
>
> #define CHIMERIC_TYPE StringAndVectorOfInts
> DEFINE_CHIMERIC_TYPE_METHODS(c_str,pop_back)
> DEFINE_CHIMERIC_TYPE_BASES (std::string,std::vector<int>)
>
> char const *PopAndCstr( chimeric_ref_StringAndVectorOfInts arg )
> {
> arg.pop_back();
> return arg.c_str();
> }
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Now its looks and work exactly like proxy proposal:
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p0957r5.pdf
And that proposal is even more generic as it allows any type to bind
to a proxy as long as it can implement a given interface.

Propobaby only thing that that proposal have inferior would be how call look:

```
p.invoke<op::Draw>();
```

Instead of yours

```
p.Draw();
```

Received on 2022-12-02 09:26:22