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();
}
<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