I'm writing a Roslyn analyzer and have come across the need to know the type of a tuple. I've retrieved the TypeInfo and in the debugger I can see there is a TupleElements hanging off the Type which would be exactly what I need. However it appears only to be accessible by casting to a TupleTypeSymbol
((Microsoft.CodeAnalysis.CSharp.Symbols.TupleTypeSymbol)typeInfo.Type).TupleElements
TupleTypeSymbol is inaccessible due to it's protection level so the cast is not possible. Is there some other way to access the information?
I have much the same question in the scenarios where my type is an open generic: is there some way to access the type information of the generics?
For the tuple types you just need to convert your type to INamedTypeSymbol and take from it the underlying tuple type: (type as INamedTypeSymbol)?.TupleUnderlyingType, after that you will get the normally ITypeSymbol of a closed generic type, and finally, just take generic type arguments: (type as INamedTypeSymbol)?.TupleUnderlyingType.TypeArguments
If you want to get info about an open generic type parameters, T1 and T2 in the Gen<T1,T2> for example, you actually can do the same thing: cast your type to INamedTypeSymbol and take TypeParameters from it, if type is open or closed generic type
Related
I have an vector of std::type_index, which indicate the trait types that a particular node has. I'm implementing a function which checks whether the node supports a particular type. It looks like this:
std::vector<std::type_index> traits;
...
template <typename T>
bool hasTrait() {
return std::find(traits.begin(), traits.end(), typeid(T)) != traits.end();
}
However, this won't work if type T is a derived type of some base type in traits. In order to fix this problem, I wanted to use std::is_convertible.
However, I only have access to the std::type_index of the type, so I can't do that. Something like this would be required: std::is_convertible<traitTypeIndex::type, T>
At first I would mention that it is surely impossible with std::is_convertible. Like all other things from type_traits, std::is_convertibleis a purely compile-time thing. But you want it to give you answer during the run-time for some run-time argument (which is type_index).
The second question is if this check can be implemented at all for arbitrary polymorphic types (by "arbitrary" I mean that you don't have any specific design-time or run-time information). I think that it's not impossible because the whole run-time reflection we have in C++ is dynamic_cast (when RTTI is on). However, even in dynamic_cast we have one semi-dynamic argument (pointer or reference) and one static (type to which we wan't to convert). I write semi-dynamic because it needs to be a pointer or reference to some certain type, it cannot absolutely type-erased argument (like void*). I believe that to check dynamically if one of two types is the inheritor of the other one we need more support from a run-time.
I've been given a bunch of dummy functions, each one with its own return type, number (and types) of arguments and I'm trying to figure out a way to create function pointers of the correct type to them automatically, then store them inside a map to be retrieved at will. In a nutshell, I'm stuck at creating the actual function pointers. The way of storing them in a map is a separate, follow-up question, due to their variable types.
I think that templates are the way to go, and I've tried creating a templated function that returns the appropriately-typed pointer given the address and types of a function. I think it could not be possible though, so any input is appreciated.
Code for the aforementioned function:
template <typename retType, typename ... argTypes> retType makeFuncPtr(void* funcAddr) {
retType (*ptr)(argTypes) = funcAddr;
return ptr;
}
I'm getting an error "Declaration type contains unexpanded parameter pack 'argTypes'". What am I doing wrong and also which is the appropriate return type for this function, as I'm not actually sure about it?
The error you ask about is because in the line:
retType (*ptr)(argTypes) = funcAddr;
there is no ... after argTypes. Note this would not actually fix the situation because a void pointer can not be converted to some other kind of pointer without a cast. And also you could not convert the function pointer to retType.
If the functions have different signatures this is a fairly tricky problem, I suggest you take a look at libffi, the tricky part here is not storing the function pointers (so long as they are not non-static member functions you can simply cast to void * and store that), the tricky part is using the stored pointer value to make a call.
libffi gives you the ability to describe a function's calling convention, return type and expected arguments. You could then write code that compares the arguments you actually received and either convert or produce an error as appropriate. With C++ it would even be possible to produce that description programmatically (your template function would take a function pointer as a parameter then use the parameter pack to map to the libffi argument type values).
Is there any way in C++ to create runtime-modificable collection that matches integer to template type?
First I though about:
std::map<uint32_t, std::type_index> type;
but std::type_index has very small usefulness. I need to be able to cast by that type and use it as argument for std::is_convertible
So the api should be able to something like that:
my_collection.add<1234, std::string>();
my_collection.get<1234>()::type // type is std::string
Or actually anything else close enough I can use in runtime :)
No.
If your list of types you support can be finitely and centrally enumerated, std::variant or boost::variant or a roll-your-own can be used.
If your list of operations on the type you support can be finitely and centrally enumerated, std::any or boost::any together with type erasure techniques can be used to solve your problem. Here is an overly generic system to type erase nearly any single-dispatch operation.
You can use std::any or boots::any to have a non-centrally yet locally finitely enumerated list of types, but only the exact types known at each enumeration location are in play at that location.
You can do a combination of the above.
Failing that, you are entering the world of runtime compiling of dynamic C++ libraries and passing the result, and/orraw C++ with source code, around. Doing on the fly compiling.
All of this will depend on what your exact, actual problem is for which that you came up with this as a "solution"; there is probably going to be a related question for which your answer is "yes", and that related question is probably what you actually need to solve.
But the answer to your question as posed is simply "No".
How can I get an underlying type from ITypeSymbol for IEnumerable<MyType>? I see ITypeSymbol.OriginalDefinition contains link to IEnumerable<>, but where can I get ITypeSymbol for MyType?
Generic type parameters are a feature of named types (as opposed to arrays or pointers).
You need to cast to INamedTypeSymbol; you can then look at the TypeArguments property.
Side note: To get the open generic type, use ConstructedFrom, not OriginalDefinition.
For a rules engine developed in C++, one of the core features is the value type. What I have so far is a bit like a COM-style VARIANT - each value knows its type. There are some rules for type conversion but it's a bit messy.
I wondered if there are nice drop-in value classes I could use which solve this, without requiring me to use a whole pre-built system. For instance maybe boost has something?
Looking for boost::any or boost::variant?
There are basically three types of variant implementations:
A type that can be freely casted between types (think untyped languages) -- boost::lexical_cast is your friend here, or boost::variant...
A type that can hold any type, but is typesafe -- e.g. initialized with an int, stays an int and doesn't allow to be treated implicitly like anything else -- this is the boost::any type
The evil allow anything type -- cast to what you want without error checking, no type information held -- think void*