Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Any type to TValue


This question is not answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 10 - Last Post: Nov 23, 2014 8:25 PM Last Post By: Remy Lebeau (Te...
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Any type to TValue  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 20, 2014 12:13 PM
Hello everyone

I am trying to create a template function to convert any data type to a TValue.
But i am facing problems with converting arrays to TValue, what i wanna do is
convert something like TStringDynArray to one TValue variable not to an "array of
TValue".

So when i try to convert like the following i get this error:

TStringDynArray s;
s.Length = 5;
 
s[0] = "Mido";
s[1] = "2";
s[2] = "3";
s[3] = "4";
s[4] = "5";
 
TValue v = TValue::From<TStringDynArray>(s);
 
if (v.IsArray())
	{
	ShowMessage(v.GetArrayElement(0).ToString()); // Error here
	
//First chance exception at $500DB4EB. Exception class $C0000005 with 
message 'access violation at 0x500db4eb: read of address 0xec8b5590'. 
Process Project1.exe (5028)


Also i can't get to convert from "const char*" to TValue as in the following
example it shows that loading an image file failed because of that.

template <class T>
TValue ToValue(const T Data)
{
return TValue::From<T>(Data);
}
//---------------------------------------------------------------------------
UnicodeString s = "test.jpg";
 
ImageControl1->StylesData["image"] = ToValue(s);//works fine and loads the bitmap
 
ImageControl1->StylesData["image"] = ToValue("test.jpg");//Loading Bitmap Failed ((unknown)).


I need help in converting array to TValue and make the template function
accept constants or converts them automatically to Delphi types.

Any help is appreciated

--
The limits of my language mean the limits of my world
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Any type to TValue  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 20, 2014 4:24 PM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed wrote:

ShowMessage(v.GetArrayElement(0).ToString()); // Error here
//First chance exception at $500DB4EB. Exception class $C0000005 with
message 'access violation at 0x500db4eb: read of address 0xec8b5590'.

Works fine in Delph, so it has to be an incompatibility in the way Delphi
and C++ handle RTTI for dynamic arrays.

Also i can't get to convert from "const char*" to TValue as in the
following example it shows that loading an image file failed because
of that.

Assigning a TValue to StylesData["image"] ultimately passes the TValue to
the LoadFromFile() method of an internal TBitmap object, using TValue.ToString()
to convert the TValue data into a UnicodeString. However, TValue.ToString()
DOES NOT support converting char* (or wchar*) values to UnicodeString!

In Delphi, the RTTI stored within a TValue for a PAnsiChar has a TypeKind
of tkPointer and a Name of "PAnsiChar". TValue.ToString() returns "(pointer
@ %p)" (where "%p" is the actual numeric value of the pointer) for tkPointer
types without regard to their Name.

In C++, the RTTI stored within a TValue for a char* has a TypeKind of tkUnknown
(which is wrong!) and a Name of "char". TValue.ToString() returns "(unknown)"
for tkUnknown values.

TValue's RTTI in C++ is provided by the C++ compiler's __delphirtti() intrinsic
function, which is returning bad RTTI for char* (and wchar_t*) pointers.
I have filed a bug report for that (https://quality.embarcadero.com/browse/RSP-9751).

So you are SOL either way. TValue simply cannot be used to pass char* data
to StylesData["image"]. You will have to convert your char* data to UnicodeString
before TValue sees it, such as with a template specialization:

template <class T>
TValue ToValue(const T Data)
{
    return TValue::From<T>(Data);
}
 
template<>
TValue ToValue(const char* Data)
{
    return TValue::From<UnicodeString>(Data);
}


--
Remy Lebeau (TeamB)
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: Any type to TValue  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 21, 2014 1:57 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Thanks Remy very much for creating a bug report,

But i am facing another weird problem now, even if i passed a Bitmap to a TValue i get an error and i have to do like this:

Image1->DataTValue::_op_Implicit(Bitmap) // works fine
 
Image1->Data = TValue::From<TBitmap*>(Bitmap); // raise Error


I don't know why it works fine for the first one and not the second. i wanted to assign any kind of data as a template to convert it self.

Should i create another function to convert objects now, then i should have used "_op_Implicit" without bothering my self.

--
The limits of my language mean the limits of my world
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Any type to TValue  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 21, 2014 4:05 PM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed wrote:

Image1->DataTValue::_op_Implicit(Bitmap) // works fine

I assume you mean "...->Data = TValue::..." instead.

TValue has an _op_Implicit() method that accepts a TObject* as input, and
TBitmap derives from TObject.

Image1->Data = TValue::From<TBitmap*>(Bitmap); // raise Error

What kind of error exactly? You need to be more specific.

TValue::_op_Implicit(TObject*) does some extra work that TValue::From<TObject*>
does not. Specifically, _op_Implicit() obtains the object's actual RTTI
using the TObject::ClassInfo() method. If ClassInfo() returns NULL, then
_op_Implicit() falls back to TValue::From<TObject*>().

I don't know why it works fine for the first one and not the second.

Different operations, different semantics.

Should i create another function to convert objects now

Sounds like it, yes:

template <class T>
TValue ToValue(const T Data)
{
    return TValue::From<T>(Data);
}
 
template<>
TValue ToValue(const char* Data)
{
    return TValue::From<UnicodeString>(Data);
}
 
template<>
TValue ToValue(const TObject* Data)
{
    return TValue::_op_Implicit(Data);
}


--
Remy Lebeau (TeamB)
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: Any type to TValue  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 21, 2014 6:39 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Sorry for the wrong code and I get this error:

First chance exception at $7522B760. Exception class 
EBitmapLoadingFailed with message 'Loading bitmap failed ().'. 
Process Project1.exe (5932)


Why doesn't it work like with "const char*" also i tried your final function
and it doesn't work too with the same error. if i am going to create a template
function for each type then there is no need to create them in the first place and just
use TValue methods. i wanted to create a single function to handle all data type.

I wonder if using "auto" as parameter instead of template might fix the problem
but that works with 64-bit only.

I don't know why they use TValue in the first place wouldn't be much better
to use Variant as it will work fine with database Fields values as well for live-binding
for example.
--
The limits of my language mean the limits of my world
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Any type to TValue  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 21, 2014 10:54 PM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed wrote:

Sorry for the wrong code and I get this error:

First chance exception at $7522B760. Exception class
EBitmapLoadingFailed with message 'Loading bitmap failed ().'.
Process Project1.exe (5932)

You are not making any sense. What are you loading exactly? The code you
showed indicates that you already have a TBitmap, so what is being loaded
into what? What are you trying to accomplish?

also i tried your final function and it doesn't work too with the same
error.

You said TValue::_op_Implicit(Bitmap) works, now you are saying it doesn't.
Which is it?

if i am going to create a template function for each type then there
is no need to create them in the first place

Sure, there is- to provide a unified interface for your code. As you have
already seen, different parameters may require different TValue methods to
be called.

i wanted to create a single function to handle all data type.

That is exact what the template functions are providing for you. They are
hiding the ugliness of TValue and C++Builder's RTTI.

I wonder if using "auto" as parameter instead of template might fix the
problem

You can't use 'auto' in a function parameter, only in a variable.

I don't know why they use TValue in the first place wouldn't be much
better to use Variant as it will work fine with database Fields values as
well for live-binding for example.

Variant has more overhead to it. TValue is meant to be lighter-weight.

--
Remy Lebeau (TeamB)
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: Any type to TValue  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 22, 2014 5:33 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
I meant this function:

template <class T>
TValue ToValue(const T Data)
{
return TValue::From<T>(Data);
}
//---------------------------------------------------------------------------
template<>
TValue ToValue(const char* Data)
{
return TValue::From<UnicodeString>(Data);
}
//---------------------------------------------------------------------------
template<>
TValue ToValue(const TObject* Data)        //doesn’t work
{
return TValue::_op_Implicit(Data);
}
//---------------------------------------------------------------------------
 
TBitmap *Bitmap = new TBitmap(0,0);
Bitmap->LoadFromFile(AppPath + "test.jpg");
 
Image1->Data = ToValue(Bitmap);


And here is what i am trying to do:

I want to create something similar to WPF “ContentControl” and
“ItemsControl” but with these names respectively “TDataControl”
and “TItemsControl”. The TItemsControl will be derived from
TDataControl and I will try to make this class “Data” property to do
the same thing as

Conten in WPF, also any control inherited from TDataControl must
has a control within its style that has a “StyleName” of “data” and the
SetData method algorithm will be like this:

If the TValue assigned is inherited from TControl then this control is
added as a child to “TDataControl” with alignment of Client if not then
it will be assigned to the StylesData like this:

StylesData[“data”] = Value;


In the TItemsControl “there will be a property similar to WPF
ItemsSource but called “ItemsData” and it will be a TValue too but
will only accept a Value that contains an array “NOT AN ARRAY OF
TVALUES”

In order to make an example like this works fine:

TItemsControl *cont = new TItemsControl(this);
cont->ItemsData = ToValue(TDirectory::GetFiles(aPath, “.bmp”);


ItemsData should create new TDataControl items as many as the
length of the assigned array. Off course there will be a DefaultItemStyle
to handle the styling of newly created items inside ItemsData.

But I got to ask you this if created those template functions in a Delphi Unit
and used in C++ will that make it work fine.

--
The limits of my language mean the limits of my world

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Any type to TValue  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 22, 2014 12:25 PM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed wrote:

template<>
TValue ToValue(const TObject* Data) //doesn’t work

In what way exactly does it not work? What exactly are you doing with the
TValue that does not work?

If the TValue assigned is inherited from TControl then this control is
added as a child to “TDataControl” with alignment of Client if not
then it will be assigned to the StylesData like this:

StylesData[“data”] = Value;

And is there a problem doing that?

In the TItemsControl “there will be a property similar to WPF
ItemsSource but called “ItemsData” and it will be a TValue too but
will only accept a Value that contains an array “NOT AN ARRAY OF
TVALUES”

And is there a problem doing that?

In order to make an example like this works fine:

TItemsControl *cont = new TItemsControl(this);
cont->ItemsData = ToValue(TDirectory::GetFiles(aPath, “.bmp”);


ItemsData should create new TDataControl items as many as the length
of the assigned array.

And is there a problem doing that?

--
Remy Lebeau (TeamB)
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: Any type to TValue  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 22, 2014 11:49 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
I meant the last function that takes the TObject as a parameter
When i try to Convert from a TBitmap to TValue it gives me the following error:

template <class T>
TValue ToValue(const T Data)
{
return TValue::From<T>(Data);
}
//---------------------------------------------------------------------------
template<>
TValue ToValue(const char* Data)
{
return TValue::From<UnicodeString>(Data);
}
//---------------------------------------------------------------------------
template<>
TValue ToValue(const TObject* Data)        //doesn’t work
{
return TValue::_op_Implicit(Data);
}
//---------------------------------------------------------------------------
 
TBitmap *Bitmap = new TBitmap(0,0);
Bitmap->LoadFromFile(AppPath + "test.jpg");
 
Image1->Data = ToValue(Bitmap); //TValue ToValue(const TObject* Data) 
 
It Raised that error
//First chance exception at $7522B760. Exception class
//EBitmapLoadingFailed with message 'Loading bitmap failed ().'.
//Process Project1.exe (5932)


Also for the TItemsControl::ItemsData property; if the following code failed
then it will fail with the property as well as you said before:

Works fine in Delphi, so it has to be an incompatibility in the way Delphi
and C++ handle RTTI for dynamic arrays.

Even if i tried to convert a TStringDynArray to TValue not a
DynamicArray<TBitmap*> it will fail.

TStringDynArray s;
s.Length = 5;
 
s[0] = "Mido";
s[1] = "2";
s[2] = "3";
s[3] = "4";
s[4] = "5";
 
TValue v = TValue::From<TStringDynArray>(s);
 
if (v.IsArray())
	{
	ShowMessage(v.GetArrayElement(0).ToString()); // Error here
	}
	
//First chance exception at $500DB4EB. Exception class $C0000005 with 
message 'access violation at 0x500db4eb: read of address 0xec8b5590'. 
Process Project1.exe (5028)


This code won't work and will raise the above error.

TItemsControl *cont = new TItemsControl(this);
cont->ItemsData = ToValue(TDirectory::GetFiles(aPath, “.bmp”);


The overridden method of SetData will be something like this:

void __fastcall TDataControl::SetData(TValue Value)
{
 
if (Value.IsObject())
	{
	if (Value.AsObject()->InheritsFrom(__classid(TControl)))
		{
		TControl *content = ((TControl *)Value.AsObject());
		content->Parent = this;
		content->Algin = Client;
		}
	else
		StylesData["data"] = Value;
	}
else
	StylesData["data"] = Value;
}


The SetItemsData method of TItemsControl will be something like this too:

void __fastcall TItemsControl::SetItemsData(TValue Value)
{
TValue V;
if Value.IsArray())
	{
	for (int i = 0; i < Value.GetArrayLength(); i++)
		{
		V = Value.GetArrayElement(i); //This will raise Error in C++ not delphi as you said
		TDataControl * Item = new TDataControl(this);
		Item->Data = V; //
		Item->Parent = this;
		ItemsList->Add(Item);
		}
	}
}


Now based on the above tests if i tried any of those it will just fail
with Array and any value inherited from TObject, strings, TDateTime. etc;

typedef DynamicArray<TBitmap*> TBitmapList;
 
TBitmapList BitmapList;
 
//Loading bitmap files here
 
//An instance of TItemsControl
ItemsControl->ItemsData = TValue::From<TBitmapList>(BitmapList); //This will fail inside the Setter function
//Or
ItemsControl->ItemsData = ToValue(BitmapList); //This will fail by not converting the dynamic array 

Also embarcadero should create opertator methods (=) with any of the supported
data types as i don't think i need to convert a string every time to TValue

TValue must be more flixble

Also if created Delphi functions to handle the template function and array Value should that work?

TValue& operator =(const UnicodeString str)
{
return TValue::From<UnicodeString>(str);
}
//---------------------------------------------------------------------------
TValue& operator =(const TObject* obj)
{
return TValue::_op_Implicit(obj);
}
//---------------------------------------------------------------------------
//etc


--
The limits of my language mean the limits of my world
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Any type to TValue  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 23, 2014 8:25 PM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed wrote:

Exception class EBitmapLoadingFailed with message 'Loading bitmap failed
().'

There are only one condition that raises an EBitmapLoadingFailed exception
with that particular error message format - when TBitmap.LoadFromFile() fails
to load a file. The text in between the parenthesis is the filename specified.
So this error suggests that the filename is blank. That has nothing to
do with the code you showed.

--
Remy Lebeau (TeamB)
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: Any type to TValue  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 23, 2014 12:18 AM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Remy,

Are you there?
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02