Do C++ Templates play nicely with VCL classes? - delphi

I'm trying to use C++ Template 'mixins' to create some new VCL components with shared additional functionality. Example...
template <class T> class Mixin : public T
{
private:
typedef T inherited;
// ...additional methods
public:
Mixin(TComponent *owner) : inherited(owner)
{
// .. do stuff here
};
};
Used like this:
class MyLabel : public Mixin<TLabel>
{
....
}
class MyEdit : public Mixin<TEdit>
{
....
}
Now, everything compiles fine, and the mixin stuff seems to work - until I try and save the component to a stream using TStream->WriteComponent, where the inherited properties (eg TLabel.Width/Height/etc.) don't get written. This is even with a 'null' mixin like the one shown above.
My code works fine when just deriving classes directly from TForm, TEdit, etc - and the class is correctly registered with the streaming system.

The quick/simple answer is: no; when dealing with a template, the compiler won't generate the proper descriptors to make streaming working. However, since this has come up before, I peeked under the cover to find out what's missing. And what I found is that it's almost there. So here's a little more information.
Upfront the compiler will never treat a template-based type as a Delphi. For example, do something like this:
void testing()
{
__classid(Mixin<Stdctrls::TLabel>); // Error Here
}
... and you'll see the error
"Error E2242 test.cpp 53: __classid requires Delphi style class type (i.e. class marked __declspec(delphiclass) or derived from System::TObject) in function testing()"
This basically says the compiler does not consider this type/class as compatible with Delphi-classes [i.e. those that derive from TObject]. Internally there's just a flag on the symbol that says whether the type is delphi-compatible or not. And I noticed that I could trick the compiler into marking the type as delphi-style if I forced it to walk up the hierarchy.. which is something it has to do if I create an instance of the object. So, with this hack the error goes away:
void testing()
{
typedef Mixin<Stdctrls::TLabel> __ttype;
std::auto_ptr<__ttype> c2(new __ttype(0));
__classid(Mixin<Stdctrls::TLabel>); // No more errors here
}
But much nicer was actually to use the __declspec(delphiclass) directly on the template, as in:
template <class T>
class __declspec(delphiclass) Mixin : public T {
private:
int i;
typedef T inherited;
public:
__fastcall Mixin(TComponent *owner) : inherited(owner) {};
};
So now that the compiler treats the type as a delphi-style class without hacks, I peeked a little more and found the issue you're probably running into: Delphi classes have the TTypeData.PropCount field - http://docwiki.embarcadero.com/VCL/en/TypInfo.TTypeData - which is a sum of the class' properties, including those of its base classes. Due to the way the various pieces of information are computed, the compiler writes out a '0' for that field when a template is involved:(
You can see this by printing out the PropCount, as in:
#include <Stdctrls.hpp>
#include <cstdio>
#include <memory>
#include <utilcls.h>
class TCppComp : public Classes::TComponent {
int i;
public:
__fastcall TCppComp(TComponent* owner): Classes::TComponent(owner) {};
__published:
__property int AAAA = {read=i, write=i};
};
template <class T>
class __declspec(delphiclass) Mixin : public T {
private:
int i;
typedef T inherited;
public:
__fastcall Mixin(TComponent *owner) : inherited(owner) {};
};
typedef Mixin<TCppComp> TMixinComp;
void showProps(TClass meta) {
PTypeInfo pInfo = PTypeInfo(meta->ClassInfo());
int Count = GetPropList(pInfo, tkAny, NULL);
TAPtr<PPropInfo> List(new PPropInfo[Count]);
std::printf("Class: %s - Total Props:%d\n",
AnsiString(pInfo->Name).c_str(), Count);
GetPropList(pInfo, tkAny, *(reinterpret_cast<PPropList*>(&List)));
for (int i = 0; i < Count; i++) {
AnsiString propName(List[i]->Name);
std::printf("\t%s\n", propName.c_str());
}
}
void test() {
showProps(__classid(TCppComp));
showProps(__classid(TMixinComp));
}
int main() {
test();
return 0;
}
When run the above prints:
Class: TCppComp - Total Props:3
AAAA
Name
Tag
Class: #%Mixin$8TCppComp% - Total Props:0
IOW, Mixin shows up with '0' published properties while its base type has 3:(
I suspect the streaming system relies on this count and that's why inherited properties are not being written out in your setup.
I considered tweaking the generated descriptors at runtime but since we write them to _TEXT it's bound to trigger DEP.
I'll look at the logic that computes the PropCount to see if there's some way to get it to compute the correct number. If time allows, please do open a QC for this: now that I've peek underneath, I believe it would not require much effort to get this working as expected.
Cheers,
Bruneau
PS: In my sample I even had the Mixin publish a property and the compiler generated the correct descriptor for that property; however, the total count was still zero.

Related

"Property reference" of the class

Is there a reference to a class property in C++Builder, analogous to a regular reference in C++? To understand what I mean, I will give the code (so far this is my solution to the problem):
void change(TControl* object) {
struct TAccessor : TControl { __property Text; };
static_cast<TAccessor*>(object)->Text = L"some text";
}
This function allows you to change the Text property of any object inherited from TControl.
But maybe there is a more elegant solution to this problem?
Your approach will update the Text of any TControl, even if it doesn't actually expose access to Text (which is declared protected in TControl itself, derived classes decide whether to promote it to public/__published as needed).
To account for that fact, you would have to use RTTI to discover if Text is accessible or not. You can also use RTTI to set the property value, without resorting to the Accessor trick.
For example, old-style RTTI (via the <TypInfo.hpp> header) works only with __published properties, nothing else, eg:
#include <TypInfo.hpp>
void change(TControl* object) {
if (IsPublishedProp(object, _D("Text"))
SetStrProp(object, _D("Text"), _D("some text"));
}
Alternatively:
#include <TypInfo.hpp>
void change(TControl* object) {
PPropInfo prop = GetPropInfo(object, _D("Text"), TTypeKinds() << tkUString);
if (prop)
SetStrProp(object, prop, _D("some text"));
}
Whereas newer-style Extended RTTI (via the <Rtti.hpp> header) supports fields, methods, and properties, and all the supported member visibilities, eg:
#include <Rtti.hpp>
typedef Set<TMemberVisibility, mvPrivate, mvPublished> TMemberVisibilitySet;
void change(TControl* object) {
static const TMemberVisibilitySet WantedVisibilities = TMemberVisibilitySet() << mvPublic << mvPublished;
TRttiContext ctx;
TRttiType *type = ctx.GetType(object->ClassType());
TRttiProperty* prop = type->GetProperty(_D("Text"));
if ((prop) && (WantedVisibilities.Contains(prop->Visibility)) && (prop->IsWritable))
prop->SetValue(object, _D("some text"));
}

pragma solidity - compilation error in jpmorganchase cakeshop

I am running a simple code from SimpleStorage example and just added few lines on top of it which I was using for my other contracts. The contract compiles fine from truffle. But on the Cakeshop Integrated IDE it shows compilation error.
pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
contract SimpleStorage {
uint public storedData;
event Change(string message, uint newVal);
function SimpleStorage(uint initVal) {
Change("initialized", initVal);
storedData = initVal;
}
function set(uint x) {
Change("set", x);
storedData = x;
}
function get() constant returns (uint retVal) {
return storedData;
}
}
It should compile on the cakeshop web UI as it compiles on local machine
Utilizing Remix, it seems the following could be potential issues with your contract:
You are using the Contract name for the constructor. You should use the constructor keyword instead.
All of your functions are missing visibility modifiers. Consider adding the public modifier to each function including the constructor.
Events should be invoked using the emit keyword. Example: emit Change("set", x);

declaring TBitmap globally

I would like to declare a TBitmap Globally.
I tried as follows:
Locally within a method, this works fine
std::auto_ptr<Graphics::TBitmap> RenderGraphic(new Graphics::TBitmap());
OR
Graphics::TBitmap * RenderGraphic = new Graphics::TBitmap;
So to declare it globally I tried this in the header file
Graphics::TBitmap *RenderGraphic;
And this in the constructor
__fastcall TShipGraphic::TShipGraphic(TComponent* Owner)
: TForm(Owner)
{
Graphics::TBitmap * RenderGraphic = new Graphics::TBitmap;
}
Which compiles fine but when running, throws an access violation exception at the first occurrence of
RenderGraphic->Canvas->Pen->Color = clBlack;
Please advise, tks in advance.
The reference source I was using is C++ Builder Graphics Introduction
which suggested the declaration in the constructor
You need to implement a singleton. Consider read-only case (bitmap is created once, no setter function).
In MyGraphics.h define accessor function
#include <vcl.h>
TBitmap* GetRenderGraphic();
Implementation in MyGraphics.cpp
static std::unique_ptr<TBitmap> renderGraphic(new TBitmap());
TBitmap* GetRenderGraphic()
{
return renderGraphic.get();
}
Use it (required including of MyGraphics.h)
GetRenderGraphic()->Canvas->Pen->Color = clBlack;

What is the correct way to define MQL4 "#import of static class methods"?

What I'm trying to achieve is define classes (using MQL4) in separate files and use the methods from those classes in the main code. Essentially importing static class member functions.
class example{ // ____ in example.mq4
public:
static void myfunction(void) export { .. do something .. }
}
class example{ // ____ in example.mqh
public:
static void myfunction(void);
}
#include <example.mqh> // ____ in main.mq4:
#import "example.ex4"
void example::myfunction(void);
#import
Results in a compile error when using the function as follows:
void OnInit(){
example::myfunction();
}
compiler error:
myfunction: function must have a body
(note example.mq4 is compiled to example.ex4 and can be imported ok)
"new"-MQL4 syntax is evolving
for the indicated purpose,
the class definition syntax shall be enough, upon instantiation of a class, its public methods are possible to be invoked on instance-objects.
Compile-time syntax:
Exporting a function without it's class-inheritance ( taking together the whole class container ) does not fit the OOP concept. This is clearly visible in the OnInit() call, where your code attempts to call a function, which is in fact a class-based object-method at a moment, where there has not yet been instantiated any object, on which the method ought to be performed anObjectINSTANCE.aClassOrInstanceMETHOD().
So, just #include
class example{ // ____ in example.mqh
public:
static void myfunction() { .. do something; }
}
// ---------------------------- // ____ in main.mq4
#property strict // "new"-MQL4
#include <example.mqh> // include
example anObject; // create a globally visible instance
// ----------------------------
void OnInit(){
anObject.myfunction(); // request <anObject> to perform <myfunction> method on self
return( EMPTY ); // "new"-MQL4 insists on return even on void fun()
}

How to create private variables in Dart?

I want to create a private variable but I cannot.
Here is my code:
void main() {
var b = new B();
b.testB();
}
class A {
int _private = 0;
testA() {
print('int value: $_private');
_private = 5;
}
}
class B extends A {
String _private;
testB() {
_private = 'Hello';
print('String value: $_private');
testA();
print('String value: $_private');
}
}
When I run this code, I get the following result:
String value: Hello
int value: Hello
Breaking on exception: type 'int' is not a subtype of type 'String' of 'value'.
Also I not get any error or warnings when editing this source code.
How can I create a private variable in Dart?
From Dart documentation:
Unlike Java, Dart doesn’t have the keywords public, protected, and private. If an identifier starts with an underscore _, it’s private to its library.
Libraries not only provide APIs, but are a unit of privacy: identifiers that start with an underscore _ are visible only inside the library.
A few words about libraries:
Every Dart app is a library, even if it doesn’t use a library directive. The import and library directives can help you create a modular and shareable code base.
You may have heard of the part directive, which allows you to split a library into multiple Dart files.
Dart documentation "libraries-and-visibility"
Privacy in Dart exists at the library, rather than the class level.
If you were to put class A into a separate library file (eg, other.dart), such as:
library other;
class A {
int _private = 0;
testA() {
print('int value: $_private'); // 0
_private = 5;
print('int value: $_private'); // 5
}
}
and then import it into your main app, such as:
import 'other.dart';
void main() {
var b = new B();
b.testB();
}
class B extends A {
String _private;
testB() {
_private = 'Hello';
print('String value: $_private'); // Hello
testA();
print('String value: $_private'); // Hello
}
}
You get the expected output:
String value: Hello
int value: 0
int value: 5
String value: Hello
In dart '_' is used before the variable name to declare it as private. Unlike other programming languages, here private doesn't mean it is available only to the class it is in, private means it is accessible in the library it is in and not accessible to other libraries. A library can consists of multiple dart files as well using part and part of. For more information on Dart libraries, check this.
The top answer as of now is definitely correct.
I'll try to go into more detail in this answer.
I'll answer the question, but lead with this: That's just not how Dart is intended to be written, partly because library-private members make it easier to define operators like ==. (Private variables of a second object couldn't be seen for the comparison.)
Now that we've got that out of the way, I'll start out by showing you how it's meant to be done (library-private instead of class-private), and then show you how to make a variable class-private if you still really want that. Here we go.
If one class has no business seeing variables on another class, you might ask yourself whether they really belong in the same library:
//This should be in a separate library from main() for the reason stated in the main method below.
class MyClass {
//Library private variable
int _val = 0;
int get val => _val;
set val(int v) => _val = (v < 0) ? _val : v;
MyClass.fromVal(int val) : _val = val;
}
void main() {
MyClass mc = MyClass.fromVal(1);
mc.val = -1;
print(mc.val); //1
//main() MUST BE IN A SEPARATE LIBRARY TO
//PREVENT MODIFYING THE BACKING FIELDS LIKE:
mc._val = 6;
print(mc.val); //6
}
That should be good. However if you really want private class data:
Though you technically aren't allowed to create private variables, you could emulate it using the following closure technique. (HOWEVER, you should CAREFULLY consider whether you really need it and whether there is a better, more Dart-like way to do what you're trying to accomplish!)
//A "workaround" that you should THINK TWICE before using because:
//1. The syntax is verbose.
//2. Both closure variables and any methods needing to access
// the closure variables must be defined inside a base constructor.
//3. Those methods require typedefs to ensure correct signatures.
typedef int IntGetter();
typedef void IntSetter(int value);
class MyClass {
IntGetter getVal;
IntSetter setVal;
MyClass.base() {
//Closure variable
int _val = 0;
//Methods defined within constructor closure
getVal = ()=>_val;
setVal = (int v) => _val = (v < 0) ? _val : v;
}
factory MyClass.fromVal(int val) {
MyClass result = MyClass.base();
result.setVal(val);
return result;
}
}
void main() {
MyClass mc = MyClass.fromVal(1);
mc.setVal(-1); //Fails
print(mc.getVal());
//On the upside, you can't access _val
//mc._val = 6; //Doesn't compile.
}
So yeah. Just be careful and try to follow the language's best-practices and you should be fine.
EDIT
Apparently there's a new typedef syntax that's preferred for Dart 2. If you're using Dart 2 you should use that. Or, even better, use inline function types.
If you use the second, it will be less verbose, but the other problems remain.

Resources