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: 656 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: 656 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: 656 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  
 |  
	| 
		
	 | 
 
 
 |  
	| 
		
 |  
	| 
		
 |  
	| 
		
 |  
	
		
		
			| Re: Make THISFN simpler and more powerful [message #60925 is a reply to message #60924] | 
			Tue, 08 October 2024 20:01    | 
		 
		
			
				
				
				
					
						  
						Lance
						 Messages: 656 Registered: March 2007 
						
					 | 
					Contributor   | 
					 | 
		 
		 
	 | 
 
	
		Didier wrote on Tue, 08 October 2024 13:25Hello Lance, 
 
What compilers do with bit field is not covered by a standard and is implementation defined... so they do just about whatever they want. 
BUT, something important is missing in you're code ! If you really want everything to be side by side, bit wise, you have to specify PACKED option on you're structs 
search the web : __attribute__((packed, aligned(X)))     or  
This will force the compiler to 'pack' all the bits together not waisting anything : so you will have a stable size. 
 
Note : positionning of the inside the struct is implementation defined ... so some compilers put them in on order, and others the other way around   
==> you're code won't be very portable  
 
 
Thanks for your reply, Didier. 
 
I am fine with padding. I am having issues with the way MSVC padding this one to unnecessary increase object size. 
 
Also, for union, I expect objects taking same memory address. MSVC failed to deliver. I don't know what the standard says. But it's a tradition dated back to old C. 
 
Are compiler free to reorder data members with the same access privileges? I will have to double check. Thanks again.
		
		
		
 |  
	| 
		
	 | 
 
 
 |  
	| 
		
 |  
	
		
		
			| Re: Make THISFN simpler and more powerful [message #60927 is a reply to message #60926] | 
			Wed, 09 October 2024 16:09    | 
		 
		
			
				
				
				
					
						  
						Lance
						 Messages: 656 Registered: March 2007 
						
					 | 
					Contributor   | 
					 | 
		 
		 
	 | 
 
	
		I don't like that fact that compilers are allowed to stuff random padding bits in a bitfield as they like, but it's actually standard compliant.  
 
In the above example, change unsigned to byte (Upp::byte of course) actually removes the extra cost on total storage usage. But the padding MSVC inserts vs GCC's sequential packed bits will result in binary incompatibilities. Worse, some old c tricks no longer work with MSVC. 
 
A somewhat more realistic though simplified example. 
class SomeFormat{
...
private:
    Font font;
    Color paper, ink, highlight;
    union{
       int32 dummy;
       struct{
           byte info1:3;
           byte info2:5;
           
           // allow individual font properties
           // to be Null for multi-tier composition
           bool faceNotNull:1;
           bool heightNotNull:1;
           bool widthNotNull:1;
           bool boldNotNull:1;
           bool strikeoutNotNull:1;
           bool underlineNotNull:1;
           bool italicNotNull:1;
           
       };
    };
    
};
 
 
In old c days, if we want to check if all Font properties are set, we can simply 
bool SomeFormat::AllFontPropertiesSet()const
{
#define SOMEFORMAT_MASK (((1<<7)-1)<<8)
    return (dummy & SOMEFORMAT_MASK) == SOMEFORMAT_MASK;
#define SOMEFORMAT_MASK
}
 
 
And to mark all font properties as set(non-Null) 
SomeFormat::SetAllFontProperties()
{
#define SOMEFORMAT_MASK (((1<<7)-1)<<8)
    return dummy |= SOMEFORMAT_MASK;
#define SOMEFORMAT_MASK
}
 
 
etc. With GCC, you can still do things like that. Total predictability. Fully appreciated.  
 
End of the day, what benefits MSVC is going to achieve by padding random bits? I can see if a bitfield crosses a machine's fast-integer boundary (a few bits in previous FAST-INTEGER and a few in the following), there will be extra cpu cost involved. Other than that, what's going to be saved? 
 
Thumbs down for MSVC on this regard.
		
		
		[Updated on: Wed, 09 October 2024 16:12] Report message to a moderator  
 |  
	| 
		
	 | 
 
 
 |  
	| 
		
 |  
	
		
		
			| Re: Make THISFN simpler and more powerful [message #60929 is a reply to message #60928] | 
			Wed, 09 October 2024 19:32    | 
		 
		
			
				
				
				
					
						  
						Didier
						 Messages: 736 Registered: November 2008  Location: France
						
					 | 
					Contributor   | 
					 | 
		 
		 
	 | 
 
	
		In fact the extra padding inserted by compilers is intented for alignement issues (although for bitfields this should not be an issue) this is why you're code works. 
But apparently MSVC has his own way of working and pack(1) doesn't seem to be taken into account ... very strange 
		
		
		[Updated on: Wed, 09 October 2024 19:37] Report message to a moderator  
 |  
	| 
		
	 | 
 
 
 |  
	| 
		
 |  
	| 
		
 |  
	
		
		
			| Re: Make THISFN simpler and more powerful [message #61061 is a reply to message #60932] | 
			Tue, 05 November 2024 02:25    | 
		 
		
			
				
				
				
					
						  
						Lance
						 Messages: 656 Registered: March 2007 
						
					 | 
					Contributor   | 
					 | 
		 
		 
	 | 
 
	
		I had a brief discussion with regard to constexpr with Mirek a few days ago 
here 
 
Today I did a simple test with a more complicated case. 
 
#include <Core/Core.h>
using namespace Upp;
CONSOLE_APP_MAIN
{
	Color c(200,50,76);
	if ( c == Color(200, 50, 76) )
	{
		RLOG("Yes");
	}else{
		RLOG("NO");
	}
}
 
 
Compiled to the following 338 lines of assembly code 
	.text
	.file	"TestColorConstant.cpp"
	.globl	main                            # -- Begin function main
	.p2align	4, 0x90
	.type	main,@function
main:                                   # @main
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$32, %rsp
	movl	$0, -4(%rbp)
	movl	%edi, -8(%rbp)
	movq	%rsi, -16(%rbp)
	movq	%rdx, -24(%rbp)
	movl	-8(%rbp), %edi
	movq	-16(%rbp), %rsi
	movq	-24(%rbp), %rdx
	callq	_ZN3Upp9AppInit__EiPPKcS2_@PLT
	leaq	_Z14ConsoleMainFn_v(%rip), %rdi
	callq	_ZN3Upp12AppExecute__EPFvvE@PLT
	callq	_ZN3Upp9AppExit__Ev@PLT
	callq	_ZN3Upp11GetExitCodeEv@PLT
	addq	$32, %rsp
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end0:
	.size	main, .Lfunc_end0-main
	.cfi_endproc
                                        # -- End function
	.globl	_Z14ConsoleMainFn_v             # -- Begin function _Z14ConsoleMainFn_v
	.p2align	4, 0x90
	.type	_Z14ConsoleMainFn_v,@function
_Z14ConsoleMainFn_v:                    # @_Z14ConsoleMainFn_v
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$16, %rsp
	leaq	-4(%rbp), %rdi
	movl	$200, %esi
	movl	$50, %edx
	movl	$76, %ecx
	callq	_ZN3Upp5ColorC2Eiii
	leaq	-8(%rbp), %rdi
	movl	$200, %esi
	movl	$50, %edx
	movl	$76, %ecx
	callq	_ZN3Upp5ColorC2Eiii
	movl	-8(%rbp), %esi
	leaq	-4(%rbp), %rdi
	callq	_ZNK3Upp5ColoreqES0_
	testb	$1, %al
	jne	.LBB1_1
	jmp	.LBB1_2
.LBB1_1:
	callq	_ZN3Upp6VppLogEv@PLT
	movq	%rax, %rdi
	leaq	.L.str(%rip), %rsi
	callq	_ZN3UpplsERNS_6StreamEPKc
	movq	%rax, %rdi
	xorl	%esi, %esi
	callq	_ZN3Upp6StreamlsENS_7EOLenumE
	jmp	.LBB1_3
.LBB1_2:
	callq	_ZN3Upp6VppLogEv@PLT
	movq	%rax, %rdi
	leaq	.L.str.1(%rip), %rsi
	callq	_ZN3UpplsERNS_6StreamEPKc
	movq	%rax, %rdi
	xorl	%esi, %esi
	callq	_ZN3Upp6StreamlsENS_7EOLenumE
.LBB1_3:
	addq	$16, %rsp
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end1:
	.size	_Z14ConsoleMainFn_v, .Lfunc_end1-_Z14ConsoleMainFn_v
	.cfi_endproc
                                        # -- End function
	.section	.text._ZN3Upp5ColorC2Eiii,"axG",@progbits,_ZN3Upp5ColorC2Eiii,comdat
	.weak	_ZN3Upp5ColorC2Eiii             # -- Begin function _ZN3Upp5ColorC2Eiii
	.p2align	4, 0x90
	.type	_ZN3Upp5ColorC2Eiii,@function
_ZN3Upp5ColorC2Eiii:                    # @_ZN3Upp5ColorC2Eiii
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$32, %rsp
	movq	%rdi, -8(%rbp)
	movl	%esi, -12(%rbp)
	movl	%edx, -16(%rbp)
	movl	%ecx, -20(%rbp)
	movq	-8(%rbp), %rax
	movq	%rax, -32(%rbp)                 # 8-byte Spill
	movl	-12(%rbp), %eax
	movb	%al, %dl
	movl	-16(%rbp), %eax
	movb	%al, %cl
	movl	-20(%rbp), %eax
                                        # kill: def $al killed $al killed $eax
	movzbl	%dl, %edi
	movzbl	%cl, %esi
	movzbl	%al, %edx
	callq	_ZN3Upp3RGBEhhh
	movl	%eax, %ecx
	movq	-32(%rbp), %rax                 # 8-byte Reload
	movl	%ecx, (%rax)
	addq	$32, %rsp
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end2:
	.size	_ZN3Upp5ColorC2Eiii, .Lfunc_end2-_ZN3Upp5ColorC2Eiii
	.cfi_endproc
                                        # -- End function
	.section	.text._ZNK3Upp5ColoreqES0_,"axG",@progbits,_ZNK3Upp5ColoreqES0_,comdat
	.weak	_ZNK3Upp5ColoreqES0_            # -- Begin function _ZNK3Upp5ColoreqES0_
	.p2align	4, 0x90
	.type	_ZNK3Upp5ColoreqES0_,@function
_ZNK3Upp5ColoreqES0_:                   # @_ZNK3Upp5ColoreqES0_
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	movl	%esi, -4(%rbp)
	movq	%rdi, -16(%rbp)
	movq	-16(%rbp), %rax
	movl	(%rax), %eax
	cmpl	-4(%rbp), %eax
	sete	%al
	andb	$1, %al
	movzbl	%al, %eax
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end3:
	.size	_ZNK3Upp5ColoreqES0_, .Lfunc_end3-_ZNK3Upp5ColoreqES0_
	.cfi_endproc
                                        # -- End function
	.section	.text._ZN3UpplsERNS_6StreamEPKc,"axG",@progbits,_ZN3UpplsERNS_6StreamEPKc,comdat
	.weak	_ZN3UpplsERNS_6StreamEPKc       # -- Begin function _ZN3UpplsERNS_6StreamEPKc
	.p2align	4, 0x90
	.type	_ZN3UpplsERNS_6StreamEPKc,@function
_ZN3UpplsERNS_6StreamEPKc:              # @_ZN3UpplsERNS_6StreamEPKc
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$16, %rsp
	movq	%rdi, -8(%rbp)
	movq	%rsi, -16(%rbp)
	movq	-8(%rbp), %rdi
	movq	-16(%rbp), %rsi
	callq	_ZN3Upp6Stream3PutEPKc@PLT
	movq	-8(%rbp), %rax
	addq	$16, %rsp
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end4:
	.size	_ZN3UpplsERNS_6StreamEPKc, .Lfunc_end4-_ZN3UpplsERNS_6StreamEPKc
	.cfi_endproc
                                        # -- End function
	.section	.text._ZN3Upp6StreamlsENS_7EOLenumE,"axG",@progbits,_ZN3Upp6StreamlsENS_7EOLenumE,comdat
	.weak	_ZN3Upp6StreamlsENS_7EOLenumE   # -- Begin function _ZN3Upp6StreamlsENS_7EOLenumE
	.p2align	4, 0x90
	.type	_ZN3Upp6StreamlsENS_7EOLenumE,@function
_ZN3Upp6StreamlsENS_7EOLenumE:          # @_ZN3Upp6StreamlsENS_7EOLenumE
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$32, %rsp
	movq	%rdi, -8(%rbp)
	movl	%esi, -12(%rbp)
	movq	-8(%rbp), %rdi
	movq	%rdi, -24(%rbp)                 # 8-byte Spill
	callq	_ZN3Upp6Stream6PutEolEv
	movq	-24(%rbp), %rax                 # 8-byte Reload
	addq	$32, %rsp
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end5:
	.size	_ZN3Upp6StreamlsENS_7EOLenumE, .Lfunc_end5-_ZN3Upp6StreamlsENS_7EOLenumE
	.cfi_endproc
                                        # -- End function
	.section	.text._ZN3Upp3RGBEhhh,"axG",@progbits,_ZN3Upp3RGBEhhh,comdat
	.weak	_ZN3Upp3RGBEhhh                 # -- Begin function _ZN3Upp3RGBEhhh
	.p2align	4, 0x90
	.type	_ZN3Upp3RGBEhhh,@function
_ZN3Upp3RGBEhhh:                        # @_ZN3Upp3RGBEhhh
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	movb	%dl, %al
	movb	%sil, %cl
	movb	%dil, %dl
	movb	%dl, -1(%rbp)
	movb	%cl, -2(%rbp)
	movb	%al, -3(%rbp)
	movzbl	-1(%rbp), %eax
	movzbl	-2(%rbp), %ecx
	shll	$8, %ecx
	orl	%ecx, %eax
	movzbl	-3(%rbp), %ecx
	shll	$16, %ecx
	orl	%ecx, %eax
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end6:
	.size	_ZN3Upp3RGBEhhh, .Lfunc_end6-_ZN3Upp3RGBEhhh
	.cfi_endproc
                                        # -- End function
	.section	.text._ZN3Upp6Stream6PutEolEv,"axG",@progbits,_ZN3Upp6Stream6PutEolEv,comdat
	.weak	_ZN3Upp6Stream6PutEolEv         # -- Begin function _ZN3Upp6Stream6PutEolEv
	.p2align	4, 0x90
	.type	_ZN3Upp6Stream6PutEolEv,@function
_ZN3Upp6Stream6PutEolEv:                # @_ZN3Upp6Stream6PutEolEv
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$16, %rsp
	movq	%rdi, -8(%rbp)
	movq	-8(%rbp), %rdi
	movl	$10, %esi
	callq	_ZN3Upp6Stream3PutEi
	addq	$16, %rsp
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end7:
	.size	_ZN3Upp6Stream6PutEolEv, .Lfunc_end7-_ZN3Upp6Stream6PutEolEv
	.cfi_endproc
                                        # -- End function
	.section	.text._ZN3Upp6Stream3PutEi,"axG",@progbits,_ZN3Upp6Stream3PutEi,comdat
	.weak	_ZN3Upp6Stream3PutEi            # -- Begin function _ZN3Upp6Stream3PutEi
	.p2align	4, 0x90
	.type	_ZN3Upp6Stream3PutEi,@function
_ZN3Upp6Stream3PutEi:                   # @_ZN3Upp6Stream3PutEi
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$32, %rsp
	movq	%rdi, -8(%rbp)
	movl	%esi, -12(%rbp)
	movq	-8(%rbp), %rcx
	movq	%rcx, -24(%rbp)                 # 8-byte Spill
	movq	24(%rcx), %rax
	cmpq	40(%rcx), %rax
	jae	.LBB8_2
# %bb.1:
	movq	-24(%rbp), %rdx                 # 8-byte Reload
	movl	-12(%rbp), %eax
	movb	%al, %cl
	movq	24(%rdx), %rax
	movq	%rax, %rsi
	addq	$1, %rsi
	movq	%rsi, 24(%rdx)
	movb	%cl, (%rax)
	jmp	.LBB8_3
.LBB8_2:
	movq	-24(%rbp), %rdi                 # 8-byte Reload
	movl	-12(%rbp), %esi
	movq	(%rdi), %rax
	callq	*(%rax)
.LBB8_3:
	addq	$32, %rsp
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end8:
	.size	_ZN3Upp6Stream3PutEi, .Lfunc_end8-_ZN3Upp6Stream3PutEi
	.cfi_endproc
                                        # -- End function
	.type	.L.str,@object                  # @.str
	.section	.rodata.str1.1,"aMS",@progbits,1
.L.str:
	.asciz	"Yes"
	.size	.L.str, 4
	.type	.L.str.1,@object                # @.str.1
.L.str.1:
	.asciz	"NO"
	.size	.L.str.1, 3
	.section	".linker-options","e",@llvm_linker_options
	.ident	"Ubuntu clang version 18.1.3 (1ubuntu1)"
	.section	".note.GNU-stack","",@progbits
	.addrsig
	.addrsig_sym _ZN3Upp9AppInit__EiPPKcS2_
	.addrsig_sym _ZN3Upp12AppExecute__EPFvvE
	.addrsig_sym _Z14ConsoleMainFn_v
	.addrsig_sym _ZN3Upp9AppExit__Ev
	.addrsig_sym _ZN3Upp11GetExitCodeEv
	.addrsig_sym _ZNK3Upp5ColoreqES0_
	.addrsig_sym _ZN3UpplsERNS_6StreamEPKc
	.addrsig_sym _ZN3Upp6VppLogEv
	.addrsig_sym _ZN3Upp6StreamlsENS_7EOLenumE
	.addrsig_sym _ZN3Upp3RGBEhhh
	.addrsig_sym _ZN3Upp6Stream3PutEPKc
	.addrsig_sym _ZN3Upp6Stream6PutEolEv
	.addrsig_sym _ZN3Upp6Stream3PutEi
 
 
While the if constexpr version  
#include <Core/Core.h>
using namespace Upp;
CONSOLE_APP_MAIN
{
	constexpr Color c(200,50,76);
	if constexpr ( c == Color(200, 50, 76) )
	{
		RLOG("Yes");
	}else{
		RLOG("NO");
	}
}
 
compiles to the following 214 lines of assembly code 
	.text
	.file	"TestColorConstant.cpp"
	.globl	main                            # -- Begin function main
	.p2align	4, 0x90
	.type	main,@function
main:                                   # @main
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$32, %rsp
	movl	$0, -4(%rbp)
	movl	%edi, -8(%rbp)
	movq	%rsi, -16(%rbp)
	movq	%rdx, -24(%rbp)
	movl	-8(%rbp), %edi
	movq	-16(%rbp), %rsi
	movq	-24(%rbp), %rdx
	callq	_ZN3Upp9AppInit__EiPPKcS2_@PLT
	leaq	_Z14ConsoleMainFn_v(%rip), %rdi
	callq	_ZN3Upp12AppExecute__EPFvvE@PLT
	callq	_ZN3Upp9AppExit__Ev@PLT
	callq	_ZN3Upp11GetExitCodeEv@PLT
	addq	$32, %rsp
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end0:
	.size	main, .Lfunc_end0-main
	.cfi_endproc
                                        # -- End function
	.globl	_Z14ConsoleMainFn_v             # -- Begin function _Z14ConsoleMainFn_v
	.p2align	4, 0x90
	.type	_Z14ConsoleMainFn_v,@function
_Z14ConsoleMainFn_v:                    # @_Z14ConsoleMainFn_v
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$16, %rsp
	movl	.L__const._Z14ConsoleMainFn_v.c(%rip), %eax
	movl	%eax, -4(%rbp)
	callq	_ZN3Upp6VppLogEv@PLT
	movq	%rax, %rdi
	leaq	.L.str(%rip), %rsi
	callq	_ZN3UpplsERNS_6StreamEPKc
	movq	%rax, %rdi
	xorl	%esi, %esi
	callq	_ZN3Upp6StreamlsENS_7EOLenumE
	addq	$16, %rsp
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end1:
	.size	_Z14ConsoleMainFn_v, .Lfunc_end1-_Z14ConsoleMainFn_v
	.cfi_endproc
                                        # -- End function
	.section	.text._ZN3UpplsERNS_6StreamEPKc,"axG",@progbits,_ZN3UpplsERNS_6StreamEPKc,comdat
	.weak	_ZN3UpplsERNS_6StreamEPKc       # -- Begin function _ZN3UpplsERNS_6StreamEPKc
	.p2align	4, 0x90
	.type	_ZN3UpplsERNS_6StreamEPKc,@function
_ZN3UpplsERNS_6StreamEPKc:              # @_ZN3UpplsERNS_6StreamEPKc
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$16, %rsp
	movq	%rdi, -8(%rbp)
	movq	%rsi, -16(%rbp)
	movq	-8(%rbp), %rdi
	movq	-16(%rbp), %rsi
	callq	_ZN3Upp6Stream3PutEPKc@PLT
	movq	-8(%rbp), %rax
	addq	$16, %rsp
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end2:
	.size	_ZN3UpplsERNS_6StreamEPKc, .Lfunc_end2-_ZN3UpplsERNS_6StreamEPKc
	.cfi_endproc
                                        # -- End function
	.section	.text._ZN3Upp6StreamlsENS_7EOLenumE,"axG",@progbits,_ZN3Upp6StreamlsENS_7EOLenumE,comdat
	.weak	_ZN3Upp6StreamlsENS_7EOLenumE   # -- Begin function _ZN3Upp6StreamlsENS_7EOLenumE
	.p2align	4, 0x90
	.type	_ZN3Upp6StreamlsENS_7EOLenumE,@function
_ZN3Upp6StreamlsENS_7EOLenumE:          # @_ZN3Upp6StreamlsENS_7EOLenumE
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$32, %rsp
	movq	%rdi, -8(%rbp)
	movl	%esi, -12(%rbp)
	movq	-8(%rbp), %rdi
	movq	%rdi, -24(%rbp)                 # 8-byte Spill
	callq	_ZN3Upp6Stream6PutEolEv
	movq	-24(%rbp), %rax                 # 8-byte Reload
	addq	$32, %rsp
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end3:
	.size	_ZN3Upp6StreamlsENS_7EOLenumE, .Lfunc_end3-_ZN3Upp6StreamlsENS_7EOLenumE
	.cfi_endproc
                                        # -- End function
	.section	.text._ZN3Upp6Stream6PutEolEv,"axG",@progbits,_ZN3Upp6Stream6PutEolEv,comdat
	.weak	_ZN3Upp6Stream6PutEolEv         # -- Begin function _ZN3Upp6Stream6PutEolEv
	.p2align	4, 0x90
	.type	_ZN3Upp6Stream6PutEolEv,@function
_ZN3Upp6Stream6PutEolEv:                # @_ZN3Upp6Stream6PutEolEv
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$16, %rsp
	movq	%rdi, -8(%rbp)
	movq	-8(%rbp), %rdi
	movl	$10, %esi
	callq	_ZN3Upp6Stream3PutEi
	addq	$16, %rsp
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end4:
	.size	_ZN3Upp6Stream6PutEolEv, .Lfunc_end4-_ZN3Upp6Stream6PutEolEv
	.cfi_endproc
                                        # -- End function
	.section	.text._ZN3Upp6Stream3PutEi,"axG",@progbits,_ZN3Upp6Stream3PutEi,comdat
	.weak	_ZN3Upp6Stream3PutEi            # -- Begin function _ZN3Upp6Stream3PutEi
	.p2align	4, 0x90
	.type	_ZN3Upp6Stream3PutEi,@function
_ZN3Upp6Stream3PutEi:                   # @_ZN3Upp6Stream3PutEi
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$32, %rsp
	movq	%rdi, -8(%rbp)
	movl	%esi, -12(%rbp)
	movq	-8(%rbp), %rcx
	movq	%rcx, -24(%rbp)                 # 8-byte Spill
	movq	24(%rcx), %rax
	cmpq	40(%rcx), %rax
	jae	.LBB5_2
# %bb.1:
	movq	-24(%rbp), %rdx                 # 8-byte Reload
	movl	-12(%rbp), %eax
	movb	%al, %cl
	movq	24(%rdx), %rax
	movq	%rax, %rsi
	addq	$1, %rsi
	movq	%rsi, 24(%rdx)
	movb	%cl, (%rax)
	jmp	.LBB5_3
.LBB5_2:
	movq	-24(%rbp), %rdi                 # 8-byte Reload
	movl	-12(%rbp), %esi
	movq	(%rdi), %rax
	callq	*(%rax)
.LBB5_3:
	addq	$32, %rsp
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end5:
	.size	_ZN3Upp6Stream3PutEi, .Lfunc_end5-_ZN3Upp6Stream3PutEi
	.cfi_endproc
                                        # -- End function
	.type	.L__const._Z14ConsoleMainFn_v.c,@object # @__const._Z14ConsoleMainFn_v.c
	.section	.rodata.cst4,"aM",@progbits,4
	.p2align	2, 0x0
.L__const._Z14ConsoleMainFn_v.c:
	.long	4993736                         # 0x4c32c8
	.size	.L__const._Z14ConsoleMainFn_v.c, 4
	.type	.L.str,@object                  # @.str
	.section	.rodata.str1.1,"aMS",@progbits,1
.L.str:
	.asciz	"Yes"
	.size	.L.str, 4
	.section	".linker-options","e",@llvm_linker_options
	.ident	"Ubuntu clang version 18.1.3 (1ubuntu1)"
	.section	".note.GNU-stack","",@progbits
	.addrsig
	.addrsig_sym _ZN3Upp9AppInit__EiPPKcS2_
	.addrsig_sym _ZN3Upp12AppExecute__EPFvvE
	.addrsig_sym _Z14ConsoleMainFn_v
	.addrsig_sym _ZN3Upp9AppExit__Ev
	.addrsig_sym _ZN3Upp11GetExitCodeEv
	.addrsig_sym _ZN3UpplsERNS_6StreamEPKc
	.addrsig_sym _ZN3Upp6VppLogEv
	.addrsig_sym _ZN3Upp6StreamlsENS_7EOLenumE
	.addrsig_sym _ZN3Upp6Stream3PutEPKc
	.addrsig_sym _ZN3Upp6Stream6PutEolEv
	.addrsig_sym _ZN3Upp6Stream3PutEi
 
 
Without going into details of assembly code, we know if constexpr indeed provides additional optimization opportunities. 
 
Note in oder for the second example to compile, certain modifications are required in <Core/Color.h>, and a minimum std=c++20 might be required. 
		
		
		[Updated on: Tue, 05 November 2024 02:28] Report message to a moderator  
 |  
	| 
		
	 | 
 
 
 |  
	| 
		
 |  
	| 
		
 |  
	| 
		
 |   
Goto Forum:
 
 Current Time: Tue Nov 04 17:08:18 CET 2025 
 Total time taken to generate the page: 0.05506 seconds 
 |