C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Chimeric Pointer

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Thu, 1 Dec 2022 10:48:48 +0000
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 use a a preprocessor macro as follows to define a method within a class:

#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...);\
}

I would still need to use some sort of complex preprocessor
manipulation to easily define a type of chimeric_ref, but the
following code on GodBolt is a few steps closer:

        https://godbolt.org/z/dvrron3Tz

And I've copy-pasted the code 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 <type_traits> // is_convertible_v
#include <tuple> // tuple, std::get<>

// I have chosen to use 'is_convertible_v' instead of "is_base_of_v"
for two reasons:
// (1) The latter would accommodate non-public inheritance (we don't want that)
// (2) Currently the C++ programming language only allows Derived class pointers
// to be converted to Base class pointers. However in the future, maybe the
// Standard will be changed to allow some other kind of implicit conversion.
// I want the chimeric pointer to be versatile and future-proof so I'm
// choosing 'is_convertible_v' over the alternatives of "is_base_of_v" or
// 'derived_from'.

template<class... Bases>
class chimeric_ref {
protected:

    std::tuple<Bases*...> pointers;

public:

    template<class T>
    requires ((std::is_convertible_v<T*, Bases*> && ...))
    /* implicit */ chimeric_ref(T &obj)
    {
        // The fold expression on the next line sets
        // each of the pointers in the tuple
        ((std::get<Bases*>(pointers) = &obj), ...);
    }

    IMPLEMENT_METHOD(SetBackgroundColour);
    IMPLEMENT_METHOD(SetValue);
    IMPLEMENT_METHOD(Refresh);
};

// ================= Section 4: Test Code

void Red( chimeric_ref<Control,TextEntry> 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);
}

Received on 2022-12-01 10:49:00