"Property reference" of the class - c++builder

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"));
}

Related

TIdTCPServer's TIdContext->Data odd behaviour

To send data to multiple clients I create a TIdThreadSafeStringList in OnConnect and assign it to AContext->Data like so
AContext->Data = new TIdThreadSafeStringList
When the client disconnects, its stringlist is deleted in OnDisconnect like so
delete AContext->Data
However this results in an AV. If I zero the parameter, like so
delete AContext->Data
AContext->Data = NULL
the AV goes away. Is there some auto cleanup I'm not aware of?
Using C++ Builder 10.2.3.
Is there some auto cleanup I'm not aware of?
Yes. TIdContext derives from TIdTask, which owns the Data property. The TIdTask destructor is called after the OnDisconnect event and will free the Data object if it is not NULL.
Another (preferred) way to handle this situation is to instead derive a new class from TIdServerContext and add your TIdThreadSafeStringList to that class (and any other per-client custom functionality you want), eg:
class TMyContext : public TIdServerContext
{
public:
TIdThreadSafeStringList *MyList;
__fastcall TMyContext(TIdTCPConnection *AConnection, TIdYarn *AYarn, TIdContextThreadList *AList = NULL)
: TIdServerContext(AConnection, AYarn, AList)
{
MyList = new TIdThreadSafeStringList;
}
__fastcall ~TMyContext()
{
delete MyList;
}
//...
};
Then assign your class type to the server's ContextClass property at runtime before activating the server, eg:
__fastcall TMyForm::TMyForm(TComponent *Owner)
: TForm(Owner)
{
IdTCPServer1->ContextClass = __classid(TMyContext);
//...
}
Then, you can simply type-cast any TIdContext* pointer belonging to the server to your class type in order to access the TIdThreadSafeStringList (or other functionality):
static_cast<TMyContext*>(SomeIdContext)->MyList->...
This way, you can ignore the TIdContext::Data property altogether, or use it for other purposes, if desired.

Can normal and const constructors be defined within the same class?

In Dart, I see that it is possible to create const constructors within a class. Is it possible to mix a normal and const constructor within a class using the same fields? Or is it intended to always separate classes used for purposes of creating mutable and immutable instances?
I have tried creating a normal and const constructor in the same class. The issue is const constructors require final fields, and so if a normal constructor were to use these fields, then its instance fields would be immutable.
void main() {
Jank fj = Jank.normal(5, 'LOL');
const cj = const Jank.fixed(6, 'HA');
fj.a = 123; //cannot do this, but want to
cj.a = 456; //cannot do this, is expected
}
class Jank {
final int a;
final String b;
Jank.normal(this.a, this.b);
const Jank.fixed(this.a, this.b);
}
I want to be able to use immutable fields when using the const constructor, and use mutable fields when using the normal one. It seems to be one or the other.
You can have non-const constructors on a class with const constructors, but all fields still need to be final.
You can also use new (implicit) with a const constructor (but not the other way around).
So the difference with a non-const constructors is that the constructor can have a body but it can not do much because it can't update the classes state. It can only invoke changes to states outside of the const instance.
A way around that would be using an Expando
The constructor initializer list allows more expressions because they are not limited to the few only allowed in const context.
So in overall mixing const and non-const is rather limited and only used for edge cases.
What you could do is create a different class that implements the class with the const constructor and instantiate it transparently using a factory constructor.
class Foo {
final int value;
const Foo(this.value);
factory Foo.nonConst(int val) => _Bar(val);
}
class _Bar implements Foo {
int _value
int get value() => _value;
Bar(int val) {
_value = val * 5;
}
}

java.lang.IllegalAccessException: can not access a member of class java.util.Collections$UnmodifiableCollection with modifiers "public"

I have classes PrimitiveProperty and ComplexProperty and the interface Property. I want to create an implementation of Property which enforces an empty unmodifiable Set of Property instances as return value of Property.getProperties, e.g.
public interface Property {
Set<Property> getProperties();
}
public class ComplexProperty implements Property {
private Set<Property> properties;
//getter overrides the interface method
}
public class PrimitiveProperty implements Property {
private final static Set<Property> EMPTY_PROPS = Collections.unmodifiableSet(new HashSet<Property>(1));
#Override
public Set<Property> getProperties() {
return EMPTY_PROPS;
}
}
With Glassfish 4.0 and I'm getting
java.lang.IllegalAccessException: Class javax.el.ELUtil can not access a member of class java.util.Collections$UnmodifiableCollection with modifiers "public"
when I access the property in the leaf attribute of a Richfaces tree, e.g.
<r:tree id="aTree"
toggleType="ajax" var="item" >
<r:treeModelRecursiveAdaptor roots="#{aCtrl.roots}"
nodes="#{item.properties}" leaf="#{item.properties.isEmpty()}">
<r:treeNode>
#{item.name}
</r:treeNode>
<r:treeModelAdaptor nodes="#{item.properties}" leaf="#{item.properties.isEmpty()}"/>
</r:treeModelRecursiveAdaptor>
</r:tree>
The issue disappears if I make the EMPTY_PROPS constant modifiable (by assigning an instance of HashSet instead of the return value of Collections.unmodifiableSet) which is not my intention.
Is it possible to achieve what I want to do? Do I have to invent or use an implementation of what Collections$UnmodifiableCollection ('s subclasses) do(es) which is compatible with the JSF access needs?
Here is the problem:
leaf="#{item.properties.isEmpty()}"
You're attempting to invoke a method directly on the UnmodifiableSet instance. Although it implements Collection, which is public, the UnmodifiableSet implementation itself, where EL (read: Reflection API) is trying to find the method on the class, is not public.
Exactly this problem is reproducible in plain Java (a main() method) as follows:
Set<Object> set = Collections.unmodifiableSet(new HashSet<>());
for (Method method : set.getClass().getMethods()) {
if ("isEmpty".equals(method.getName())) {
method.invoke(set); // IllegalAccessException.
}
}
This is essentially a bug in the EL implementation used.
You'd better just use EL's own empty operator:
leaf="#{empty item.properties}"

Custom constructor in Luabind

I'm using Luabind to bind a C++ API to Lua. I have some objects that cannot be created directly, but rather must be created on another thread. I'm currently handling this by defining a "static" member called create that yields until the object is created:
luabind::class_<Foo>("Foo")
.scope
[
luabind::def("create", &someCreateMethod, luabind::yield)
]
This works, but has the disadvantage of complicating the client API. For these classes, you cannot create them normally (e.g. local f = Foo()), but instead need to do local f = Foo.create().
Is it possible to define a Luabind constructor that doesn't actually call the C++ constructor, but instead another function that returns the constructed object (and can yield in the meantime)? I've tried defining bindings for __init and __call (the latter under a scope, to define it on the class, not its instances), but I didn't have success with either approach.
Constructors in Luabind must be actual C++ class constructors. So you'll just have to deal with the slight API weirdness.
If all you're interested in is the ability to use Foo as a constructor method, then you can do this. Register your C++ class Foo as FooLua to Lua. Then, register this someCreateMethod, not as a member of FooLua, but as just a Lua free function called Foo. Thus, as far as the user is concerned, Foo is a constructor for the Lua class Foo.
Now, this will inhibit your ability to give Foo other static properties, like members and so forth. But you could accomplish that by using some direct Lua API coding. You can create an empty table Foo and create a metatable for it that forwards __index and __newindex calls to FooLua. Similarly, you can override this metatable's __call to forward the construction to Foo.create.
While luabind doesn't provide a straight-forward way of defining custom constructors, it is in fact possible with a bit of a hack:
template<typename T,auto TCnstrct,typename ...TArgs>
static void custom_constructor(luabind::argument const &self_, TArgs... args)
{
using holder_type = luabind::detail::value_holder<T>;
luabind::detail::object_rep* self = luabind::touserdata<luabind::detail::object_rep>(self_);
void* storage = self->allocate(sizeof(holder_type));
self->set_instance(new (storage) holder_type(nullptr,TCnstrct(std::forward<TArgs>(args)...)));
}
template<typename T,auto TCnstrct,typename ...TArgs>
static void define_custom_constructor(lua_State *l)
{
auto *registry = luabind::detail::class_registry::get_registry(l);
auto *crep = registry->find_class(typeid(T));
assert(crep);
auto fn = luabind::make_function(l,&custom_constructor<T,TCnstrct,TArgs...>);
crep->get_table(l);
auto o = luabind::object{luabind::from_stack(l,-1)};
luabind::detail::add_overload(o,"__init",fn);
lua_pop(l,1);
}
This will allow you to use any free function as a constructor after the class definition:
static void define_vector_class(lua_State *l)
{
auto modMath = luabind::module_(l,"math");
struct Vector
{
Vector()=default;
float x,y,z;
};
auto defVec = luabind::class_<Vector>("Vector");
modMath[defVec];
// Define custom constructor taking three float arguments
define_custom_constructor<Vector,[](float x,float y,float z) -> Vector {
Vector v;
v.x = x;
v.y = y;
v.z = z;
return v;
},float,float,float>(l); // Constructor parameter types have to be specified in template parameter list as well
}
Tested with the deboostified version of luabind (https://github.com/decimad/luabind-deboostified), but it should work with the regular version as well.

Do C++ Templates play nicely with VCL classes?

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.

Resources