|
|
Home » Extra libraries, Code snippets, applications etc. » C++ language problems and code snippets » Make THISFN simpler and more powerful (by taking advantage of some new c++ feature)
Make THISFN simpler and more powerful [message #59037] |
Tue, 18 October 2022 21:08 |
Lance
Messages: 526 Registered: March 2007
|
Contributor |
|
|
in Core/Function.h, we have THISFN defined like this
template <class Ptr, class Class, class Res, class... ArgTypes>
Function<Res (ArgTypes...)> MemFn(Ptr object, Res (Class::*method)(ArgTypes...))
{
return [=](ArgTypes... args) { return (object->*method)(args...); };
}
#define THISFN(x) MemFn(this, &CLASSNAME::x)
This can be done in C++20 with the following
#define THISFN(memfun) std::bind_front(&std::remove_cvref_t<decltype(*this)>::memfun, this)
Of course this involves only library feature (no core language features), so it should be able to be rewritten to make available in current versons of c++ compilers/libraries that UPP aims to conform to atm.
An additional benefit of above macro definition is that it relieves the library user of the burden of an otherwise useless typedef
class MyClass
{
typedef MyClass CLASSNAME;
//....
}
to be able to use thisfn
BTW, thisfn is provided in the UPP library for a good reason: there are occasions where using thisfn is so much easier than using an lambda.
eg.
menu.Set( THISFN(MenuMain) );
vs
menu.Set ( [=, this] ( Bar & bar )
{
MenuMain ( bar );
}
);
And imagine when the callback accept a few more parameters.
[/code]
U++ is currently aiming at compliance to C++14. What if you want to use it in your project and you know your compiler/c++library are modern enough?
One way is to put the following in a header file and make sure you include it after <Core/Core.h> is included.
#ifdef THISFN
# undef THISFN
# define THISFN(memfun) ....
#endif
Reference:
Why use `std::bind_front` over lambdas in C++20?
[Updated on: Tue, 18 October 2022 21:19] Report message to a moderator
|
|
|
Re: Make THISFN simpler and more powerful [message #59153 is a reply to message #59037] |
Thu, 10 November 2022 00:32 |
Lance
Messages: 526 Registered: March 2007
|
Contributor |
|
|
This is kind of C++20 related, I am going to reuse this thread for c++ language specific problems or what not.
Here I got a problem: how to detect if a class is Moveable?
A naive first thought would be
#include <Core/Core.h>
#include <concepts>
template <class T>
inline constexpr bool is_moveable = std::derived_from<T, Upp::Moveable<T>>;
using namespace Upp;
CONSOLE_APP_MAIN
{
LOG(is_moveable<Upp::Rect>);
LOG(is_moveable<Upp::String>);
}
Output
true
false
It turns out Moveable has an optional second template parameter which failed the test in [b]String[/]'s case.
What makes Moveable so special is that it introduced a friend AssertMoveable0 in <Core/Topt.h>
template <class T>
inline void AssertMoveable0(T *t) { AssertMoveablePtr(&**t, *t); }
// COMPILATION ERROR HERE MEANS TYPE T WAS NOT MARKED AS Moveable
template <class T, class B = EmptyClass>
struct Moveable : public B {
friend void AssertMoveable0(T *) {}
};
Trying to use it directly, I come up with something like
#include <Core/Core.h>
#include <concepts>
template <class T>
inline constexpr bool is_moveable = /*std::derived_from<T, Upp::Moveable<T>>;*/
requires (T t){ Upp::AssertMoveable0(&t); };
using namespace Upp;
CONSOLE_APP_MAIN
{
LOG(is_moveable<Upp::Rect>);
LOG(is_moveable<Upp::String>);
}
This time both give correct result, but unfortuately, any class T would give a true result regardless of whether it's derived from Upp::Moveable.
How would you check if a class type is Upp::Moveable ?
BTW, something like this
LOG( std::is_base_of<Ctrl, EditField>);
will fail to compile because of a missing guard in the definition of LOG in <Core/Diag.h>
#define LOG(a) UPP::VppLog() << a << UPP::EOL
I would think here change it to
#define LOG(a) UPP::VppLog() << (a) << UPP::EOL
might be a reasonable thing to do.
|
|
|
|
|
|
Re: Make THISFN simpler and more powerful [message #59158 is a reply to message #59157] |
Fri, 11 November 2022 02:50 |
Lance
Messages: 526 Registered: March 2007
|
Contributor |
|
|
Problem solved with a hackish modification to the definition of the Moveable template in <Core/Topt.h>
template <class T, class B = EmptyClass>
struct Moveable : public B {
typedef B MoveableBase; // Add this line
friend void AssertMoveable0(T *) {}
};
Now it works like a charm
#include <Core/Core.h>
#include <concepts>
#include <type_traits>
template <class T>
concept UppMoveable = std::is_trivial_v<T> || requires{
typename T::MoveableBase;
requires std::derived_from<T,
Upp::Moveable<T, typename T::MoveableBase>
>;
};
CONSOLE_APP_MAIN
{
using namespace Upp;
struct D{
D(){}
};
struct F{
F() = default;
};
struct E : Moveable<E, D>{
E(){}
};
DUMP(UppMoveable<String>);//true
DUMP(UppMoveable<D>);//false
DUMP(UppMoveable<F>);//true, note the difference between D and F
DUMP(UppMoveable<E>);//true
DUMP(UppMoveable<int64>);//true
}
This is a hack. I am still interested to know if there is a way to do it without resorting to touch <Core/Topt.h>.
[Updated on: Fri, 11 November 2022 02:59] Report message to a moderator
|
|
|
Goto Forum:
Current Time: Fri Apr 19 04:11:10 CEST 2024
Total time taken to generate the page: 0.04612 seconds
|
|
|