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