C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Chimeric Pointer

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Thu, 1 Dec 2022 15:29:08 +0000
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();
}

Received on 2022-12-01 15:29:21