Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Tutorials
Bazaar
Status & Roadmap
FAQ
Authors & License
Forums
Funding Ultimate++
Search on this site
Search in forums












SourceForge.net Logo
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)
icon10.gif  Make THISFN simpler and more powerful [message #59037] Tue, 18 October 2022 21:08 Go to next message
Lance is currently offline  Lance
Messages: 527
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 Go to previous messageGo to next message
Lance is currently offline  Lance
Messages: 527
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 #59154 is a reply to message #59153] Thu, 10 November 2022 06:29 Go to previous messageGo to next message
Oblivion is currently offline  Oblivion
Messages: 1094
Registered: August 2007
Senior Contributor
Maybe a combination of is_constructibles can help here:

using namespace Upp;

struct A {
	A(A&&) = delete;
	A&& operator=(A&&) = delete;
};

CONSOLE_APP_MAIN
{
	StdLogSetup(LOG_COUT);
	
	bool a = std::is_constructible_v<Rect, Rect&&>;
	bool b = std::is_constructible_v<String, String&&>;
	bool c = std::is_constructible_v<A, A&&>;
	RLOG(a);
	RLOG(b);
	RLOG(c);
}



Best regards,
Oblivion


[Updated on: Thu, 10 November 2022 06:30]

Report message to a moderator

Re: Make THISFN simpler and more powerful [message #59156 is a reply to message #59154] Thu, 10 November 2022 12:52 Go to previous messageGo to next message
Lance is currently offline  Lance
Messages: 527
Registered: March 2007
Contributor
Thank you, Oblivion! You code checks if a class have a move ctor?

I was looking for a way to check if a class T has Upp::Moveable<T, optional U> as its base class such that it can be put in a Upp::Vector<T>.

atm I believe the AssertMoveable0 path is dead end. Now the problem becomes:

There is a class T and some class U, devise a way to detect (at compile time of course) if T is defined with something like
class SomeT : public Moveable<SomeT, AnyU>
{...};

Re: Make THISFN simpler and more powerful [message #59157 is a reply to message #59156] Thu, 10 November 2022 21:41 Go to previous messageGo to next message
Lance is currently offline  Lance
Messages: 527
Registered: March 2007
Contributor
Some failed attempts.

template <class T>
concept UppMoveable = requires (T t){
    Upp::Vector<T> v;
    v.Add(t);
};

This will fail in compilation with a strange error message.

Turns out you cannot do variable declaration in a requires-expression.

Something like this
template <class T>
concept UppMoveable = requires (T t, Upp::Vector<T> v){
    v.Add(t);
};


compiles fine but doesn't give desired results. Compiler only check if expressions inside a requires-expression are well-formed. Evaluation doesn't take place.

So this won't work. Back to old conclusion: we need a way to check is a class T is declared/defined with something like
class MyString : public Moveable<MyString, optionalB>{...};

to determine if it can be placed in a Upp::Vector.

Here are some well written articles about concepts and requires-expression.

C++20 Concepts - a Quick Introduction

Requires-expression
Re: Make THISFN simpler and more powerful [message #59158 is a reply to message #59157] Fri, 11 November 2022 02:50 Go to previous message
Lance is currently offline  Lance
Messages: 527
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 Smile
#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

Previous Topic: Math - GaussJordan function
Goto Forum:
  


Current Time: Sat May 25 17:13:12 CEST 2024

Total time taken to generate the page: 0.01750 seconds