C++ CLI error C2228 - c++-cli

I'm working on a C++/Cli project, so I defined my struct like this.
ref struct token_t
{
public :
static TokenTypes_t TokenType; ///enum class
static String ^ TokenString; ///enum class
static Keyword_t KeywordID; ///enum class
static int IntVal;
static char CharVal;
static Operator_t OprID; ///enum class
};
I passed an instance of this struct as a function parameter, but when I tried to do something like : token.TokenString.pop_back(); it says :
Error 11 error C2228: left of '.pop_back' must have class/struct/union

Did you declare the struct statics somewhere? From your code it is not apparent if you did that or not. If you did not, then mere struct instantiation would NOT get you static member instantiation. You need to instantiate the static members somewhere. Something like
struct token_t::TokenString = "foo"; (correct the syntax if wrong)

First, a System::String (the String^ you declared) doesn't have a pop_back method. Look it up on MSDN for more info.
Second, you declared it static. You are trying to use it with an instance. That doesn't match. Most likely, you don't want any of that static stuff. Remove it.
You also need to access methods of a XXX^ type with the -> operator as if it were a normal pointer.

You need to use the arrow access operator. Other then that, you seem to use System.String as if it was std::string from the native C++ standard library...

OK, several things:
String^ is a reference type, you need to use -> rather than . when calling methods on it.
There is no method pop_back on the string class.
TokenString is declared static, therefore the proper way to access it is token_t::TokenString. If it's static, it's not associated with a particular instance of the type, only with the type itself.
You've got the type declared as ref struct. This is perfectly valid, but confusing. The ref wins out over the struct, so what you have is the same as ref class. If you want a struct (i.e., a value type, not a reference type), you should say value struct token_t. (value class will give you the same result as value struct, but that's again confusing.)
The proper members of the String class are SubString, and Length. Therefore, the line to remove the last character from the string would be this: token_t::TokenString = token_t::TokenString->SubString(0, token_t::TokenString->Length - 1);

Related

Accepting managed struct in C++/CLI both with "hat" operator and without. What is the difference?

I've got a C++/CLI layer that I've been using successfully for a long time. But I just discovered something that makes me think I need to relearn some stuff.
When my C++/CLI functions receive an instance of any managed class, they use the "hat" operator ('^') and when they receive an instance of a managed struct, they do not. I thought this was how I was supposed to write it.
To illustrate as blandly as I can
using Point = System::Windows::Point;
public ref class CppCliClass
{
String^ ReturnText(String^ text) { return text; } // Hat operator for class
Point ReturnStruct(Point pt) { return pt; } // No hat operator for struct
};
I thought this was required. It certainly works. But just today I discovered that CancellationToken is a struct, not a class. My code accepts it with a hat. I thought it was a class when I wrote it. And this code works just fine. My cancellations are honored in the C++/CLI layer.
void DoSomethingWithCancellation(CancellationToken^ token)
{
// Code that uses the token. It works just fine
}
So apparently I can choose either method.
But then what is the difference between passing in a struct by value (as I've done with every other struct type I use, like Point) and by reference (as I'm doing with CancellationToken?). Is there a difference?
^ for reference types and without for value types matches C#, but C++/CLI does give you more flexibility:
Reference type without ^ is called "stack semantics" and automatically tries to call IDisposable::Dispose on the object at the end of the variable's lifetime. It's like a C# using block, except more user-friendly. In particular:
The syntax can be used whether the type implements IDisposable or not. In C#, you can only write a using block if the type can be proved, at compile time, to implement IDisposable. C++/CLI scoped resource management works fine in generic and polymorphic cases, where some of the objects do and some do not implement IDisposable.
The syntax can be used for class members, and automatically implements IDisposable on the containing class. C# using blocks only work on local scopes.
Value types used with ^ are boxed, but with the exact type tracked statically. You'll get errors if a boxed value of a different type is passed in.

Defining type as a reference in golang

To my surprise this block
type Object *struct{
X int
}
compiles in golang. However, I don't know how to create an instance of the underlying struct.
Functionally, what I wanted to achieve is to remove all the stars from all type signatures without hacks (redefining the type and other tricks). This would make the type/structs very much like Java classes.
The question is - is this construction supported in golang? Or should I stick to putting stars everywhere?
If you don't want to pass pointers around everywhere, you don't have to. You could just pass your structs around by value.
E.g.
Define your struct as:
type Object struct{
X int
}
And then define your functions as:
func DoStuffToObject(obj Object) {
// Do things with obj here
}
There's nothing wrong with passing around objects by value if that's what you wish to do.

Difference between "struct" and "value struct"

What is the difference between
public struct X{
public:
int A;};
and
public value struct X{
public:
int A;};
How can I convert one into the other?
The first is a normal C++ structure.
Using value struct creates a C++/CLI value type (a .NET structure). You typically will want to copy from one to the other manually, though if the memory layout is the same, you can often use things like Marshal::PtrToStructure to copy the data directly. Note that this returns a boxed value struct, however, so manual copying is often more efficient.

boost::serialization polymorphic type initialization

I have a base class and 4 derived classes. I store all my derived classes in a vector of base class pointer type. During first initialization I create each derived type differently using their constructors. Basically they each have different param types in their ctors. (I had to provide a protected default ctor to make BOOST_CLASS_EXPORT compile but that's a different story). I don't/can't save all the members (filled in ctor) of these derived classes.
Now, when I load objects from the disk using boost::serialize, these members (that are not serialized and specific to each derived type) are destroyed. And, I cannot think of a way to re-initialize these derived types since I only store the base class pointers.
What exactly I need is being able to load my derived types (pointers) partially, without deleting all their content..
Is there a way to overcome this, a magic boost define or function call perhaps? Otherwise, polymorphism with boost::serialize is not possible at all.. I should be missing something and hope I could define my problem good enough.
You shouldn't need to create a default constructor just for serialization. You can instead have boost save/load the data needed by a non-default constructor, and use that to construct new objects when loading.
That way, whatever your constructors do to ensure the validity of data members can also happen during serialization, and the serialization library never has to manipulate the data members of your objects directly. This should prevent data erasure.
For example, if your class can be constructed using a name and a size, you could overload the functions as follows:
template <class Archive>
inline void save_construct_data(Archive & ar, const my_class * t, const unsigned int) {
ar << my_class->name();
ar << my_class->size();
}
template<class Archive>
inline void load_construct_data(Archive & ar, my_class * t, const unsigned int) {
std::string name;
int size;
ar >> name;
ar >> size;
::new(t)my_class(name, size); // placement 'new' using your regular constructor
}
Check out the docs here.

CIL instruction "isinst <valuetype>"

The ECMA Common Language Infrastructure documentation says this about the CIL "isinst class" instruction:
Correct CIL ensures that class is a valid typeref or typedef or typespec token indicating a class, and
that obj is always either null or an object reference.
This implies that a valuetype is not allowed, right? But mscorlib.dll contains a method System.RuntimeTypeHandle::Equals(object obj) with the following instruction:
IL_0001: isinst System.RuntimeTypeHandle
And System.RuntimeTypeHandle is a valuetype. Can anybody put me right here?
Have a look at the declaration of RuntimeTypeHandle:
.class public sequential ansi serializable sealed beforefieldinit RuntimeTypeHandle
extends System.ValueType
implements System.Runtime.Serialization.ISerializable
Although RuntimeTypeHandle is declared as a struct its representation in CIL is some kind of special class. In other words, you can imagine structs as special classes that inherit from System.ValueType and whose attributes follow a strict order.
With that in mind isinst would be callable with RuntimeTypeHandle. For what I interpret isinst is not limited to reference types at all as long as there is a class representing the type.
Let's say we write in C#:
var i = 4;
var b = i is Int32;
We get a compiler warning
Warning: The given expression is always of the provided ('int') type.
What happens? We assign 4 to i. ibecoms an int. On the next line iis being auto-boxed to its corresponding ReferenceType (class), so that the warning is obvious. We could even write
var b = i is int;
I hope this can contribute to some kind of clearification on this topic.