I'm going over some C++/CLI material and I've come across the concept of a literal field:
literal int inchesPerFoot = 12;
Is this preferable to a const because a const FIELD can't exist because a field cannot initialize itself...so:
class aClass
{
private:
const int aConstant = 1; // Syntax error.
...
};
Thanks,
Scott
A literal field is used for compile-time constants. It is associated with the class (similar to a "static const" field). In your example aConstant is a non-static const (an instance based) field--which is why you can't initialize it at the time of declaration (it would be initialized in the ctor's initialization list).
The difference between literal and static const fields is that referencing assemblies cannot use static const fields as compile-time constants, while literals can. However, within the same assembly, static const can be used as compile time constants.
FYI,
literal is equivalent to C#'s const.
initonly is equivalent to C#'s readonly.
Related
Boost PropertyTree allows serialization of custom types by providing a specialization of translator_between, but I couldn't find any documentation, and the code can be quite cryptic.
The general pattern for a custom type CustomType is:
namespace boost {
namespace property_tree {
template<>
struct translator_between<KeyType, CustomType>
{
struct type {
typedef KeyType internal_type;
typedef CustomType external_type;
boost::optional<external_type> get_value(const internal_type& str);
boost::optional<internal_type> put_value(const external_type& obj);
};
};
} // namespace property_tree
} // namespace boost
KeyType must be std::string for ptree and iptree, and in general must be identical to the first template argument of your basic_ptree. You could make type a template if you're into that sort of thing.
The two typedefs internal_type and external_type are mandatory, they are used in detail::is_translator<Translator> in ptree_utils.hpp.
Note that you could make translator_between::type a typedef, but you don't technically need to. I suspect they do it in all the examples to make the definition marginally prettier.
The arguments of get_value and put_value don't necessarily need to be const &, but I can't think of a reason to change that.
Beware in general of where you put your declarations of translator_between, especially if the streaming operators are overloaded for your CustomType. In this case you should probably put the translator_between next to the declarations of the operators.
I tried to declare the following in my C++/CLI code.
public ref class MyClass
{
public:
const String ^MyLuckyNumber = "One";
It fails misirably during the compile phase. But in C# the following works.
public class MyClass
{
public const string NowMyLuckyNumber = "Two";
How can I declare a 'const String^' in C++/CLI?
I tried to google on it but no luck!
I believe the keyword you're looking for is literal
literal String ^MyLuckyNumber = "One";
the literal keyword implies a static const on the variable you're declaring. Also, the keyword requires an initialization during the declaration, something you'd expect from a static const declaration.
MSDN Reference
I have created a new managed, reference class in C++ cli. And now I want to overload equality of objects of this class.
public ref class DerivedFromObject {
virtual bool Equals(Object^ obj) override;
virtual int GetHashCode() override;
static bool operator!= (const DerivedFromObject%, const DerivedFromObject%);
static bool operator== (const DerivedFromObject%, const DerivedFromObject%);
}
As far as I know from C#, operator!= calls operator==, that calls Equals, which refers to GetHashCode.
bool DerivedFromObject::operator==(const DerivedFromObject % a, const DerivedFromObject % b)
{
a.Equals((Object^)%b); // Error
}
In the snippet above, Equals and GetHashCode cannot be called on a const object, that's why I cannot call Equals from operator==.
How can I mark method that doesn't change the object in C++ cli? Or What the most appropriative way to define equality chain?
There's two things here:
.Net doesn't really have the concept of const in the way that C++ does. C++/CLI will enforce the rules that C++ has, but since .Net doesn't use it, no library methods are declared const, so you'll have problems calling just about any method. Rather than being explicitly declared like in C++, it's just by convention that methods like equals don't modify their parameters.
Since you used const%, I think you were trying to parallel the C++ convention of passing const& parameters. % is more similar in usage to ** double pointer than to &: You pass things parameters as % (or ^% for reference types) when the method can assign a value to the parameter, and it should be available to the calling method.
Here's how I would implement this:
public ref class DerivedFromObject : IEquatable<DerivedFromObject> {
virtual bool Equals(DerivedFromObject^ other);
virtual bool Equals(Object^ obj) override;
virtual int GetHashCode() override;
static bool operator!= (DerivedFromObject^, DerivedFromObject^);
static bool operator== (DerivedFromObject^, DerivedFromObject^);
}
One other thing you said:
...Equals, which refers to GetHashCode.
Be careful here, because it is possible for unequal objects to have the same hash code.
GetHashCode will need to evaluate everything, and then if the hash codes are equal, then Equals need to evaluate everything again to be sure they're actually equal. It'll probably be more efficient to not look at the hash code, just compare the objects field by field, and bail out as soon as they're not equal.
The following structure:
struct match_str {
const char* s; // Pointer to string
const uint8_t l; // Length
};
Is intended to be initialized only as follows:
const match_str s = {"200 OK", 5};
and used as normal struct with constant members. During compilation time, I get the following warning:
warning #370-D: class "match_str" defines no constructor to initialize the following: const member "match_str::l"
What can I do with the warning? I get the warning, it makes sense, but I am not sure how to handle it. Basically, this is a safer c-string structure that I use in my code, and each instance is hand written like the const char*
Reference:
Is this warning alright - "#368-D: <entity> defines no constructor to initialize the following:"?
warning #411: class foo defines no constructor to initialize the following:
Just get rid of the const in the struct, and make the instances of the struct const, which will serve the purpose of keeping members constant.
Can someone please explain me the following code snippet?
value struct ValueStruct {
int x;
};
void SetValueOne(ValueStruct% ref) {
ref.x = 1;
}
void SetValueTwo(ValueStruct ref) {
ref.x = 2;
}
void SetValueThree(ValueStruct^ ref) {
ref->x = 3;
}
ValueStruct^ first = gcnew ValueStruct;
first->x = 0;
SetValueOne(*first);
ValueStruct second;
second.x = 0;
SetValueTwo(second); // am I creating a copy or what? is this copy Disposable even though value types don't have destructors?
ValueStruct^ third = gcnew ValueStruct;
third->x = 0;
SetValueThree(third); // same as the first ?
And my second question is: is there any reason to have something like that?:
ref struct RefStruct {
int x;
};
RefStruct% ref = *gcnew RefStruct;
// rather than:
// RefStruct^ ref = gcnew RefStruct;
// can I retrieve my handle from ref?
// RefStruct^ myref = ???
What is more: I see no difference between value type and ref type, since both can be pointed by handler ;(
Remember that the primary use of C++/CLI is for developing class libraries for consumption by GUIs / web services built in other .NET languages. So C++/CLI has to support both reference and value types because other .NET languages do.
Furthermore, C# can have ref parameters that are value typed as well, this isn't unique to C++/CLI and it doesn't in any way make value types equivalent to reference types.
To answer the questions in your code comments:
am I creating a copy or what?
Yes, SetValueTwo takes its parameter by value, so a copy is made.
is this copy Disposable even though value types don't have destructors?
Incorrect. Value types can have destructors. Value types cannot have finalizers. Since this particular value type has a trivial destructor, the C++/CLI compiler will not cause it to implement IDisposable. In any case, if a parameter is an IDisposable value type, the C++/CLI compiler will ensure that Dispose is called when the variable goes out of scope, just like stack semantics for local variables. This includes abnormal termination (thrown exception), and allows managed types to be used with RAII.
Both
ValueStruct% ref = *gcnew ValueStruct;
and
ValueStruct^ ref = gcnew ValueStruct;
are allowed, and put a boxed value type instance on the managed heap (which isn't a heap at all, but a FIFO queue, however Microsoft chooses to call it a heap like the native memory area for dynamic allocation).
Unlike C#, C++/CLI can keep typed handles to boxed objects.
If a tracking reference is to a value type instance on the stack or embedded in another object, then the value type content has to be boxed in the process of formed the reference.
Tracking references can also be used with reference types, and the syntax to obtain a handle is the same:
RefClass^ newinst = gcnew RefClass();
RefClass% reftoinst = *newinst;
RefClass^% reftohandle = newinst;
RefClass stacksem;
RefClass^ ssh = %stacksem;
One thing that I can never seem to remember completely is that the syntax isn't 100% consistent compared to native C++.
Declare a reference:
int& ri = i; // native
DateTime% dtr = dt; // managed tracking reference
Declare a pointer:
int* pi; // native
Stream^ sh; // tracking handle
Form a pointer:
int* pi = &ri; // address-of native object
DateTime^ dth = %dtr; // address-of managed object
Note that the unary address-of operator is the same as the reference notation in both standard C++ and C++/CLI. This seems to contradict a tracking reference cannot be used as a unary take-address operator (MSDN) which I'll get back to in a second.
First though, the inconsistency:
Form a reference from a pointer:
int& iref = *pi;
DateTime% dtref = *dth;
Note that the unary dereference operator is always *. It is the same as the pointer notation only in the native world, which is completely opposite of address-of which, as mentioned above, are always the same symbol as the reference notation.
Compilable example:
DateTime^ dth = gcnew DateTime();
DateTime% dtr = *dth;
DateTime dt = DateTime::Now;
DateTime^ dtbox = %dt;
FileInfo fi("temp.txt");
// FileInfo^ fih = &fi; causes error C3072
FileInfo^ fih = %fi;
Now, about unary address-of:
First, the MSDN article is wrong when it says:
The following sample shows that a tracking reference cannot be used as a unary take-address operator.
The correct statement is:
% is the address-of operator for creation of a tracking handle. However its use is limited as follows:
A tracking handle must point to an object on the managed heap. Reference types always exist on the managed heap so there is no problem. However, value types and native types may be on the stack (for local variables) or embedded within another object (member variables of value type). Attempts to form a tracking handle will form a handle to a boxed copy of the variable: the handle is not linked to the original variable. As a consequence of the boxing process, which requires metadata which does not exist for native types, it is never possible to have a tracking handle to an instance of a native type.
Example code:
int i = 5;
// int^ ih = %i; causes error C3071
System::Int32 si = 5;
// System::Int32^ sih = %si; causes error C3071
// error C3071: operator '%' can only be applied to an instance
// of a ref class or a value-type
If System::Int32 isn't a value type then I don't know what is. Let's try System::DateTime which is a non-primitive value type:
DateTime dt = DateTime::Now;
DateTime^ dtbox = %dt;
This works!
As a further unfortunate restriction, primitive types which have dual identity (e.g. native int and managed value type System::Int32) are not handled correctly, the % (form tracking reference) operator cannot perform boxing even when the .NET name for the type is given.