How to get information about an attribute of enum type?
I have an EClass with an attribute which is type of enum. I know you can use the following code to determine the type of an attribute
EDataType type = attr.getEAttributeType();
if (type == EcorePackage.Literals.EINT);
//do something
if (type == EcorePackage.Literals.EENUM);
// do something
But the line (type == EcorePackage.Literals.EENUM) doesn't work, thus I am wondering how to determine an attribute is type of eEnum, given any Ecore metamodels.
For enumerated types you could use either of:
type instanceof EEnum
type.eClass() == EcorePackage.eINSTANCE.getEEnum()
Related
I have a C++ class which acts like a map that can contain different data types.
In C++, it is unknown at compile time what data type an entry is. Therefore, the programmer has to know and the accessor is templated:
auto a = map.get<int>("my-int-entry");
auto b = map.get<std::string>("my-string-entry");
At runtime, the map knows what type the entries have. So in python, I should be able to use the runtime type information.
a = map.get('my-int-entry') # a is of type int
b = map.get('my-string-entry') # b is of type string
I'd like that it looks up the type information at runtime, then calls get<int> if the runtime type is int, otherwise get<std::string>. Is there a way to do this directly in pybind11?
Or do I need another (pure python) function that calls the respectively mapped C++ functions?
I'm not sure how you would query your map in runtime about what type a key has, but this is the general idea of how I would do that:
map_wrapper.def("get", [](Map& self, const std::string& key) -> py::object {
if (self.is_a<int>(key)) {
return py::cast(self.get<int>(key));
} else if (self.is_a<std::string>(key)) {
return py::cast(self.get<std::string>(key));
} else if ...
});
You would need to know the types you want to support in advance.
I am porting an existing C++ application to GO as part of an evaluation project. As part of this I need to read two Dataset attributes which in some files are stored as a double and in some as a float. The C++ code I use to handle this looks like the following (we are using the libhdf5-cpp-100 on Debian Linux).
const auto att = dataSet.openAttribute(attributeName);
if (att.getDataType() == H5::PredType::NATIVE_DOUBLE) {
att.read(att.getDataType(), &attributeValue);
}
else if (att.getDataType() == H5::PredType::NATIVE_FLOAT) {
float temp = 0.F;
att.read(att.getDataType(), &temp);
attributeValue = static_cast<double>(temp);
}
else {
// we throw an exception indicating we don't support the type
}
My problem is that I'm having trouble writing the equivalent in GO. (I'm using the package "gonum.org/v1/hdf5".) The read method seems simple enough:
func (s *Attribute) Read(data interface{}, dtype *Datatype) error
But I'm struggling to determine what to pass as the Datatype as the Attribute type does not seem to have a GetDataType method. The closest I see is the following:
func (s *Attribute) GetType() Identifier
But that doesn't return a Datatype, it returns an Identifier. I tried the following comparison on the assumption that given the Identifier I could determine the data type:
if attr.GetType().ID() == hdf5.T_NATIVE_DOUBLE.ID() {
// handle as a double
}
but that doesn't work. The ID returned from GetType() is not the same as the ID for either the double or the float.
I've been through the online docs at https://godoc.org/gonum.org/v1/hdf5 but have been unable to find the solution to my problem. (Or any example of reading HDF5 attributes using GO.)
Has anyone managed to do something like this? Or are most examples just assuming the type rather than querying it?
I have confirmed my suspicions and now have a proper answer. The essential problem is that there was an error in my use of the C++ API (which would have led to only writing 1/2 of a double in certain cases) and I was essentially trying to repeat that error in GO. In fact, the solution is very simple.
The attribute type that is passed into the attribute read method, is not the type of the attribute, it is the type that you want it converted to when stored in memory. That means that my C++ code should be much simpler as there is no need to check the attribute type, nor to static_cast it to the result. To read and store the attribute value, relying on HDF5 to perform the conversion and for a suitable exception to be thrown if the attribute is not convertible to a double, is as simple as
const auto att = dataSet.openAttribute("my attribute name");
att.read(H5::PredType::NATIVE_DOUBLE, &attributeValue);
The GO version is more work, since we have to manage the object life cycle and error conditions manually, but here it is. (Note that I'm assuming "...handle the error..." also involves an early exit, otherwise an additional if statement is needed to check that att is not nil.)
att, err := dataSet.OpenAttribute("my attribute name")
if err != nil {
...handle the error...
}
err = att.Read(&attributeValue, hdf5.T_NATIVE_DOUBLE)
if err != nil {
...handle the error...
}
err = att.Close()
if err != nil {
...handle the error...
}
I have a class titled Eclipse with a private struct member containing ~30 fields of various data types.
I have a method that will return a data field from the struct, based on a field number passed in as a parameter.
Seeing as the struct contains data of various types, I opted to use the auto keyword with a trailing return type based on a templated parameter. My method header is below.
template<typename TheType>
auto getColumnData(TheType toGet, int fieldNum) -> decltype(toGet) {
// switch statement to return fields based on fieldNum
}
If I want to return a column that is an int, I call getColumnData(0, 1);. The first parameter is only used to determine the return type of the method, and the second parameter determines the field number to return to the method caller.
Theoretically, this would cause the return type of getColumnData() to be int and return the first column (corresponding to the first field) of the struct. But I'm receiving this compilation error:
no viable conversion from returned value of type 'std::string' (aka 'basic_string<char, char_traits<char>, allocator<char> >') to function return type 'decltype(toGet)' (aka 'int')`
I understand that if I were to call this method with an int as the first parameter, and a field number that corresponds to a field returning a std::string, there would be issues. But, based on checks in other classes, this case would never occur.
Is there any way that I can force my compiler to accept this code, even if it might not be correct for certain cases?
I know that I could just overload the method, but I'd rather not have multiple different methods for basically the same purpose if I can figure out how to accomplish the task in only one.
Also, if my understanding of any of this information seems incorrect, please let me know. I'm very new to C++, so I'm just learning these features as I go.
You cannot change a method's return type dynamically at runtime like you are attempting to do. Your first parameter is not a data type known at compile-time. It is just an integer that is populated at runtime, so you can't make compile-time decisions based on it at all.
A simple solution would be to use std::variant (C++17 or later) or boost::variant (C++11 and later) as the return type:
using FieldType = std:::variant<int, std::string>;
FieldType getColumnData(int fieldNum) {
// switch statement to return fields based on fieldNum
}
int i = std::get<int>(getColumnData(1));
std::string s = std::get<std::string>(getColumnData(2));
Otherwise, you would have to make the return type be a template parameter, not a method parameter:
template<typename TheType>
TheType getColumnData(int fieldNum) {
// switch statement to return fields based on fieldNum
}
But then you run into the problem that not all fields will be convertible to the return type (can't return a std::string field when an int is requested, etc), so you can't just switch on the fieldNum since it is not evaluated at compile-time.
You might be tempted to make the field number be a template parameter so it is constant at compile-time, and then specialize on it:
template<const int FieldNum>
auto getColumnData() { return 0; };
template<> int getColumnData<1>() { return private_struct.Field1; }
template<> std::string getColumnData<2>() { return private_struct.Field2; }
// etc...
int i = getColumnData<1>();
std::string s = getColumnData<2>();
But I get errors when I try to do that on a templated class method ("explicit specialization in non-namespace scope").
You might be tempted to do something like this, and hope the compiler optimizes away the unused branches:
template<const int FieldNum>
auto getColumnData() {
if (FieldNum == 1) return private_struct.Field1;
if (FieldNum == 2) return private_struct.Field2;
//etc...
return 0;
}
or
template<const int FieldNum>
auto getColumnData()
{
switch (FieldNum) {
case 1: return private_struct.Field1;
case 2: return private_struct.Field2;
// etc...
}
return 0;
};
int i = getColumnData<1>();
std::string s = getColumnData<2>();
But that doesn't work, either ("inconsistent deduction for auto return type" errors).
I want to write a function that returns every item in a List that is not the first or the last item (a via point). The function gets a generic List<*> as input. A result should only be returned if the elements of the list are of the type Waypoint:
fun getViaPoints(list: List<*>): List<Waypoint>? {
list.forEach { if(it !is Waypoint ) return null }
val waypointList = list as? List<Waypoint> ?: return null
return waypointList.filter{ waypointList.indexOf(it) != 0 && waypointList.indexOf(it) != waypointList.lastIndex}
}
When casting the List<*> to List<Waypoint>, I get the warning:
Unchecked Cast: kotlin.collections.List
to kotlin.colletions.List
I can't figure out a way to implement it otherwise. What's the right way to implement this function without this warning?
In Kotlin, there's no way to check the generic parameters at runtime in general case (like just checking the items of a List<T>, which is only a special case), so casting a generic type to another with different generic parameters will raise a warning unless the cast lies within variance bounds.
There are different solutions, however:
You have checked the type and you are quite sure that the cast is safe. Given that, you can suppress the warning with #Suppress("UNCHECKED_CAST").
#Suppress("UNCHECKED_CAST")
val waypointList = list as? List<Waypoint> ?: return null
Use .filterIsInstance<T>() function, which checks the item types and returns a list with the items of the passed type:
val waypointList: List<Waypoint> = list.filterIsInstance<Waypoint>()
if (waypointList.size != list.size)
return null
or the same in one statement:
val waypointList = list.filterIsInstance<Waypoint>()
.apply { if (size != list.size) return null }
This will create a new list of the desired type (thus avoiding unchecked cast inside), introducing a little overhead, but in the same time it saves you from iterating through the list and checking the types (in list.foreach { ... } line), so it won't be noticeable.
Write a utility function that checks the type and returns the same list if the type is correct, thus encapsulating the cast (still unchecked from the compiler's point of view) inside it:
#Suppress("UNCHECKED_CAST")
inline fun <reified T : Any> List<*>.checkItemsAre() =
if (all { it is T })
this as List<T>
else null
With the usage:
val waypointList = list.checkItemsAre<Waypoint>() ?: return null
To improve #hotkey's answer here's my solution:
val waypointList = list.filterIsInstance<Waypoint>().takeIf { it.size == list.size }
This gives you the List<Waypoint> if all the items can be casted, null otherwise.
In case of generic classes casts cannot be checked because type information is erased in runtime. But you check that all objects in the list are Waypoints so you can just suppress the warning with #Suppress("UNCHECKED_CAST").
To avoid such warnings you have to pass a List of objects convertible to Waypoint. When you're using * but trying to access this list as a typed list you'll always need a cast and this cast will be unchecked.
I made a little variation to #hotkey answer when used to check Serializable to List objects :
#Suppress("UNCHECKED_CAST")
inline fun <reified T : Any> Serializable.checkSerializableIsListOf() =
if (this is List<*> && this.all { it is T })
this as List<T>
else null
Instead of
myGenericList.filter { it is AbstractRobotTurn } as List<AbstractRobotTurn>
I like doing
myGenericList.filter { it is AbstractRobotTurn }.map { it as AbstractRobotTurn }
Not sure how performant this is, but no warnings at least.
Kotlin ensures type safety for operations involving generics at compile time, while, at runtime, instances of generic types don't hold information about their actual type arguments. For example, List is erased to just List<*>. In general, there is no way to check whether an instance belongs to a generic type with certain type arguments at runtime.
https://kotlinlang.org/docs/typecasts.html#type-erasure-and-generic-type-checks
I'm trying to get this C++ method to return an array of b2Fixture instances. It iterates of a series of JRContact instances, which are defined like:
struct JRContact {
b2Fixture *fixtureA;
b2Fixture *fixtureB;
bool operator==(const JRContact& other) const
{
return (fixtureA == other.fixtureA) && (fixtureB == other.fixtureB);
}
};
n.b. I'm a total stranger to C++, don't hesitate to mention weird things I might have done in that code ;-)
The following fails to compile (XCode compiler on MacOS), see errors in comments:
id AbstractContactListener::getFixturesOfTypeCollidingWithFixture(b2Fixture *fix, int type){
std::vector<b2Fixture> fixtures;
std::vector<JRContact>::iterator ct;
JRContact contact;
for (ct = _contacts.begin(); ct != _contacts.end(); ct++){
contact = *ct;
if (
( (fix == contact.fixtureA) || (fix == contact.fixtureB) ) &&
( contactContainsType(contact, type) )
){
if (fix == contact.fixtureA) {
// error: Semantic Issue: Reference to type 'const value_type' (aka 'const b2Fixture') could not bind to an lvalue of type 'b2Fixture *'
fixtures.push_back(contact.fixtureB);
}
else {
// error: Semantic Issue: Reference to type 'const value_type' (aka 'const b2Fixture') could not bind to an lvalue of type 'b2Fixture *'
fixtures.push_back(contact.fixtureA);
}
}
}
// error: Semantic Issue: No viable conversion from 'std::vector<b2Fixture>' to 'id'
return fixtures;
}
Thanks for your time!
Change :
std::vector<b2Fixture> fixtures;
to :
std::vector<b2Fixture *> fixtures;
About the return type you can change it either to void* or std::vector<b2Fixture *> * and use : return &fixtures;
But pay attention the your vector is local so allocate it for not returning a pointer to an invalid location. (And ofcourse remember to free it when you done using it).
It's not really clear what you want to do, but the problem is you're telling the compiler that AbstractContactListener::getFixturesOfTypeCollidingWithFixture will return an id and you're instead returning an std::vector<b2Fixture>.
From the name of the function, I guess you might want to return a vector, so change the signature to:
std::vector<b2Fixture> AbstractContactListener::getFixturesOfTypeCollidingWithFixture
(b2Fixture *fix, int type)
You're also pushing pointers in your vector when you should be pushing objects:
fixtures.push_back(*(contact.fixtureB));
The vector fixtures holds b2Fixture instances, but the contact.fixtureA is a b2Fixture*.
Either:
dereference it:
fixtures.push_back(*(contact.fixtureA)); // Same for 'fixtureB'.
or,
change the type of fixtures:
std::vector<b2Fixture*> fixtures;
There is also a mismatch between the function return type and what is actually being returned. If you want to return fixtures, have the return type match the type of fixtures.