Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [cdt-dev] Instantiating templates with dependent arguments

An example:
#include <vector>
template<typename T>
class Stack {
std::vector<T> elems;
};
int main() {
Stack<int> intStack;
Stack<bool> boolStack;
}
intStack and boolStack both resolve to my primary template Stack. But if I resolve intStack our current context is T=int and I want to be able to also resolve the containing std::vector<T> elems to the primary template vector. By context I mean the types of all template parameters, in the above example T=int.
But if I resolve boolStack my current context is T=bool so std::vector<T> elems should resolve to the fully specialized vector template. It should resolve to the same as when I have std::vector<bool>. 

The final goal is to get an instance of ICPPSpecialization for a name, e.g. for the template-id vector<T> (where T is in the current context an int or a bool or anything else) so we can call getTemplateParameterMap() and getSpecializedBinding(). We want to know to which template a name resolves in a specific context and what the chosen template arguments are. So we want to instantiate the template even if it depends on other template arguments. The existing CDT methods return a deferred binding if a type depends on a template argument so we needed a workaround to instantiate such templates.
The described workflows are our solutions to get the ICPPSpecialization for a name/template-id and avoiding that we get a deferred binding. The first paragraph describes how we get the ICPPFunctionInstance for a function call _expression_ and the second how we instantiate a class template to get a ICPPSpecialization that is not of type ICPPUnknownBinding.

We only want to instantiate the template to later get the template definition so we can show it in our view and find further names inside the template body that depend on a template argument. Instantiating the template was the easiest way we could think of. We don’t want to change something in the user code.

Since we rely on reflection to achieve this with existing CDT methods that are not public, I asked if it is possible to change the mentioned methods so they are public or I can pass the current context (template arguments) that should be considered when resolving the name.

Is it still unclear what I mean by that? If so, what is unclear?

Marco


On Mon, Apr 20, 2015 at 4:25 PM Sergey Prigogin <eclipse.sprigogin@xxxxxxxxx> wrote:
On Mon, Apr 20, 2015 at 7:15 AM, Marco Syfrig <marco.syfrig@xxxxxxxxx> wrote:

Hi list

I’m developing a CDT plug-in to visualize template instantiations with a colleague for our bachelor thesis. The idea is that the user can select a template instance that is not deferred (e.g. std::vector<int>) and we open a new view with the vector code. The user then can open further template instances or other names that depend on a template argument. So the user can see which function overload and specialization gets chosen and the deduced template arguments.

You can see our current result in the attached image or under http://i.imgur.com/0wq8Ee4.png. Function templates and parts of class templates already work. Member functions do not yet work.

I first need to explain how and why we instantiate dependent templates:

We need to instantiate the nested templates that depend on other template arguments by ourselves since CDT does not yet support nested template instantiations.


Could you please explain what you mean by this.
 

For function templates we create a subclass of LookupData with the surrounding ICPPTemplateParameterMap and then pass this LookupData to CPPSemantics.resolveFunction(LookupData, ICPPFunction[], boolean). We then call the private CPPTemplates.instantiateForFunctionCall(ICPPFunctionTemplate, ICPPTemplateArgument[], List<IType>, List<ValueCategory>, boolean, IASTNode) via reflection to get an ICPPSpecialization with an ICPPTemplateParameterMap. We first built the ICPPTemplateParameterMap with our own code but there are too many special cases we might have missed and why should we implement it again if it already exists in CDT even if it’s not public.

For class templates we have an even uglier and unmaintainable solution. We copied the whole CPPTemplates.createBinding(ICPPASTTemplateId) method, added a new parameter to pass the ICPPTemplateParameterMap of the surrounding template instance, call all non accessible methods in the createBinding body via reflection and added an else when no template declaration could be found for the template-id. More precisely I’ve added the following else in my code.

if (hasDependentArgument(args)) {
ICPPASTTemplateDeclaration tdecl = getTemplateDeclaration(id);
if (tdecl != null) {
// ...
} else {
        for (int i = 0; i < args.length; i++) {
            ICPPTemplateArgument arg = args[i];
            IType typeValue = arg.getTypeValue();
            if (typeValue instanceof ICPPTemplateParameter) {
                args[i] = parentMap.getArgument((ICPPTemplateParameter) typeValue);
            }
        }
    }
}

Now to my question respectively my request: Would it be possible to change some methods to public or maybe default and add one method so we don’t have to call methods via reflection?
— The method org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates.instantiateForFunctionCall(ICPPFunctionTemplate, ICPPTemplateArgument[], List<IType>, List<ValueCategory>, boolean, IASTNode) should be public or the method org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates.instantiateForFunctionCall(ICPPFunction[], ICPPTemplateArgument[], List<IType>, List<ValueCategory>, boolean, IASTNode) with default visibility should have a parameter to specify whether it’s ok to have dependent types.
— org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates.createBinding(ICPPASTTemplateId) should exist in a version with a second parameter of type ICPPTemplateParameterMap with the template arguments from the surrounding template instance. But  I don‘t think my solution from above is enough and doesn’t always work.

So, would it be possible to implement those changes or would this cause to many problems? Did I miss something with my solution or is it ok?

Marco

-sergey 

_______________________________________________
cdt-dev mailing list
cdt-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/cdt-dev

_______________________________________________
cdt-dev mailing list
cdt-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/cdt-dev

Back to the top