Date: Thu, 27 Oct 2022 15:59:56 +0100
On Thu, Oct 27, 2022 at 1:45 PM Jarrad Waterloo <descender76_at_[hidden]> wrote:
>
> Your second reason is captured in the following. Please give it a look, your comments and your support.
>
> https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2603r1.html
If I understand your proposal correctly, then I've implemented it as
follows. The following code works properly with clang++ and g++ if you
do "-std=c++20".
#include <cstring> // memcpy
#include <type_traits> // is_same_v - just for debugging
#include <typeinfo> // type_info
#include <iostream> // iostream
#include <ios> // dec, hex
/* =================== First let's have some sample classes */
using std::cout;
using std::endl;
struct NumberPrinter {
long unsigned i = 0u;
virtual void Print(void) { cout << "Base class!" << endl; }
};
struct DecimalNumberPrinter : NumberPrinter {
void Print(void) { cout << std::dec << i++ << endl; }
};
struct HexadecimalNumberPrinter : NumberPrinter {
void Print(void) { cout << "0x" << std::hex << i++ << endl; }
};
/* =================== Now let's have the code for MemFuncPtr */
template<class Retval, class... Args>
class MemFuncPtrBase {
public:
std::type_info const &ti;
protected:
Retval (*const p)(void*,Args...);
MemFuncPtrBase( std::type_info const &arg_ti, Retval
(*arg_p)(void*,Args...) ) : ti(arg_ti), p(arg_p) {}
public:
/* =================================================
Beginning of class within a class */
class Invoker final {
void *const p_obj;
Retval (*const p)(void*, Args...);
public:
Invoker(void *const arg_p_obj, Retval (*const arg_p)(void*, Args...))
: p_obj(arg_p_obj), p(arg_p) {}
Retval operator()(Args... args)
{
return p(p_obj,args...);
}
};
/* End of class within a class
================================================= */
Invoker operator()(void *const arg_p)
{
return Invoker(arg_p, this->p);
}
};
template<class Retval, class T, class... Args>
class MemFuncPtrT final : public MemFuncPtrBase< Retval, Args... > {
protected:
static Retval (*Address_Of_Member_Function( Retval (T:: *const
mp)(Args...) ))(void*, Args...)
{
static T obj; // Let's hope it has a default constructor
std::uintptr_t n;
std::memcpy(&n, &mp, sizeof n);
Retval (*const *const v_table)(void*,Args...) =
*static_cast<Retval(*const**)(void*,Args...)>(static_cast<void*>(&obj));
return v_table[n >> 3u]; // This works on 'g++' and 'clang++'
}
public:
typedef MemFuncPtrBase< Retval, Args... > Base;
MemFuncPtrT( Retval (T:: *const arg)(Args...) )
: Base( typeid(T), Address_Of_Member_Function(arg) ) {}
Base &base(void) { return *this; }
};
int main(int const argc, char **const argv)
{
MemFuncPtrT mfp1( &NumberPrinter::Print );
MemFuncPtrT mfp2( &HexadecimalNumberPrinter::Print );
static_assert( std::is_same_v< decltype(mfp1)::Base, decltype(mfp2)::Base >,
"These two types should be the same");
using MemFuncPtr = decltype(mfp1)::Base;
// On the next line, we decide at runtime which method to call
MemFuncPtr mfp( (argc % 2) ? mfp1.base() : mfp2.base() );
HexadecimalNumberPrinter obj;
mfp(&obj)();
cout << mfp.ti.name() << endl;
}
>
> Your second reason is captured in the following. Please give it a look, your comments and your support.
>
> https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2603r1.html
If I understand your proposal correctly, then I've implemented it as
follows. The following code works properly with clang++ and g++ if you
do "-std=c++20".
#include <cstring> // memcpy
#include <type_traits> // is_same_v - just for debugging
#include <typeinfo> // type_info
#include <iostream> // iostream
#include <ios> // dec, hex
/* =================== First let's have some sample classes */
using std::cout;
using std::endl;
struct NumberPrinter {
long unsigned i = 0u;
virtual void Print(void) { cout << "Base class!" << endl; }
};
struct DecimalNumberPrinter : NumberPrinter {
void Print(void) { cout << std::dec << i++ << endl; }
};
struct HexadecimalNumberPrinter : NumberPrinter {
void Print(void) { cout << "0x" << std::hex << i++ << endl; }
};
/* =================== Now let's have the code for MemFuncPtr */
template<class Retval, class... Args>
class MemFuncPtrBase {
public:
std::type_info const &ti;
protected:
Retval (*const p)(void*,Args...);
MemFuncPtrBase( std::type_info const &arg_ti, Retval
(*arg_p)(void*,Args...) ) : ti(arg_ti), p(arg_p) {}
public:
/* =================================================
Beginning of class within a class */
class Invoker final {
void *const p_obj;
Retval (*const p)(void*, Args...);
public:
Invoker(void *const arg_p_obj, Retval (*const arg_p)(void*, Args...))
: p_obj(arg_p_obj), p(arg_p) {}
Retval operator()(Args... args)
{
return p(p_obj,args...);
}
};
/* End of class within a class
================================================= */
Invoker operator()(void *const arg_p)
{
return Invoker(arg_p, this->p);
}
};
template<class Retval, class T, class... Args>
class MemFuncPtrT final : public MemFuncPtrBase< Retval, Args... > {
protected:
static Retval (*Address_Of_Member_Function( Retval (T:: *const
mp)(Args...) ))(void*, Args...)
{
static T obj; // Let's hope it has a default constructor
std::uintptr_t n;
std::memcpy(&n, &mp, sizeof n);
Retval (*const *const v_table)(void*,Args...) =
*static_cast<Retval(*const**)(void*,Args...)>(static_cast<void*>(&obj));
return v_table[n >> 3u]; // This works on 'g++' and 'clang++'
}
public:
typedef MemFuncPtrBase< Retval, Args... > Base;
MemFuncPtrT( Retval (T:: *const arg)(Args...) )
: Base( typeid(T), Address_Of_Member_Function(arg) ) {}
Base &base(void) { return *this; }
};
int main(int const argc, char **const argv)
{
MemFuncPtrT mfp1( &NumberPrinter::Print );
MemFuncPtrT mfp2( &HexadecimalNumberPrinter::Print );
static_assert( std::is_same_v< decltype(mfp1)::Base, decltype(mfp2)::Base >,
"These two types should be the same");
using MemFuncPtr = decltype(mfp1)::Base;
// On the next line, we decide at runtime which method to call
MemFuncPtr mfp( (argc % 2) ? mfp1.base() : mfp2.base() );
HexadecimalNumberPrinter obj;
mfp(&obj)();
cout << mfp.ti.name() << endl;
}
Received on 2022-10-27 15:00:09