diff --git a/src/libs/cplusplus/GenTemplateInstance.cpp b/src/libs/cplusplus/GenTemplateInstance.cpp
index 07555932505a659c2069f01cbddc01d0c485e50c..d3c1c8955111ab5cd056600fb209d5a103a73d0e 100644
--- a/src/libs/cplusplus/GenTemplateInstance.cpp
+++ b/src/libs/cplusplus/GenTemplateInstance.cpp
@@ -1,145 +1,354 @@
 
 #include "GenTemplateInstance.h"
+#include "Overview.h"
+
 #include <Control.h>
 #include <Scope.h>
 #include <Names.h>
 #include <Symbols.h>
 #include <CoreTypes.h>
+#include <Literals.h>
+
 #include <QtCore/QVarLengthArray>
+#include <QtCore/QDebug>
 
 using namespace CPlusPlus;
 
-GenTemplateInstance::GenTemplateInstance(Control *control, const Substitution &substitution)
-    : _control(control),
-      _substitution(substitution)
-{ }
+namespace {
 
-FullySpecifiedType GenTemplateInstance::operator()(const FullySpecifiedType &ty)
-{ return subst(ty); }
+class ApplySubstitution
+{
+public:
+    ApplySubstitution(const LookupContext &context, const GenTemplateInstance::Substitution &substitution);
+    ~ApplySubstitution();
+
+    Control *control() const { return context.control(); }
+
+    FullySpecifiedType operator()(Name *name);
+    FullySpecifiedType operator()(const FullySpecifiedType &type);
+
+    int findSubstitution(Identifier *id) const;
+    FullySpecifiedType applySubstitution(int index) const;
+
+private:
+    class ApplyToType: protected TypeVisitor
+    {
+    public:
+        ApplyToType(ApplySubstitution *q)
+            : q(q) {}
+
+        FullySpecifiedType operator()(const FullySpecifiedType &ty)
+        {
+            FullySpecifiedType previousType = switchType(ty);
+            accept(ty.type());
+            return switchType(previousType);
+        }
+
+    protected:
+        using TypeVisitor::visit;
+
+        Control *control() const
+        { return q->control(); }
+
+        FullySpecifiedType switchType(const FullySpecifiedType &type)
+        {
+            FullySpecifiedType previousType = _type;
+            _type = type;
+            return previousType;
+        }
+
+        virtual void visit(VoidType *)
+        {
+            // nothing to do
+        }
+
+        virtual void visit(IntegerType *)
+        {
+            // nothing to do
+        }
+
+        virtual void visit(FloatType *)
+        {
+            // nothing to do
+        }
+
+        virtual void visit(PointerToMemberType *)
+        {
+            qDebug() << Q_FUNC_INFO; // ### TODO
+        }
+
+        virtual void visit(PointerType *ptrTy)
+        {
+            _type.setType(control()->pointerType(operator()(ptrTy->elementType())));
+        }
+
+        virtual void visit(ReferenceType *refTy)
+        {
+            _type.setType(control()->referenceType(operator()(refTy->elementType())));
+        }
+
+        virtual void visit(ArrayType *arrayTy)
+        {
+            _type.setType(control()->arrayType(operator()(arrayTy->elementType()), arrayTy->size()));
+        }
+
+        virtual void visit(NamedType *ty)
+        {
+            FullySpecifiedType n = q->operator ()(ty->name());
+            _type.setType(n.type());
+        }
+
+        virtual void visit(Function *funTy)
+        {
+            Function *fun = control()->newFunction(/*sourceLocation=*/ 0, funTy->name());
+            fun->setScope(funTy->scope());
+            fun->setConst(funTy->isConst());
+            fun->setVolatile(funTy->isVolatile());
+            fun->setVirtual(funTy->isVirtual());
+            fun->setAmbiguous(funTy->isAmbiguous());
+            fun->setVariadic(funTy->isVariadic());
+
+            fun->setReturnType(q->operator ()(funTy->returnType()));
+
+            for (unsigned i = 0; i < funTy->argumentCount(); ++i) {
+                Argument *originalArgument = funTy->argumentAt(i)->asArgument();
+                Argument *arg = control()->newArgument(/*sourceLocation*/ 0,
+                                                       originalArgument->name());
+
+                arg->setType(q->operator ()(originalArgument->type()));
+                arg->setInitializer(originalArgument->hasInitializer());
+                fun->arguments()->enterSymbol(arg);
+            }
+
+            _type.setType(fun);
+        }
+
+        virtual void visit(Namespace *)
+        {
+            qDebug() << Q_FUNC_INFO;
+        }
+
+        virtual void visit(Class *)
+        {
+            qDebug() << Q_FUNC_INFO;
+        }
+
+        virtual void visit(Enum *)
+        {
+            qDebug() << Q_FUNC_INFO;
+        }
+
+        virtual void visit(ForwardClassDeclaration *)
+        {
+            qDebug() << Q_FUNC_INFO;
+        }
+
+        virtual void visit(ObjCClass *)
+        {
+            qDebug() << Q_FUNC_INFO;
+        }
+
+        virtual void visit(ObjCProtocol *)
+        {
+            qDebug() << Q_FUNC_INFO;
+        }
+
+        virtual void visit(ObjCMethod *)
+        {
+            qDebug() << Q_FUNC_INFO;
+        }
+
+        virtual void visit(ObjCForwardClassDeclaration *)
+        {
+            qDebug() << Q_FUNC_INFO;
+        }
+
+        virtual void visit(ObjCForwardProtocolDeclaration *)
+        {
+            qDebug() << Q_FUNC_INFO;
+        }
+
+    private:
+        ApplySubstitution *q;
+        FullySpecifiedType _type;
+    };
+
+    class ApplyToName: protected NameVisitor
+    {
+    public:
+        ApplyToName(ApplySubstitution *q): q(q) {}
+
+        FullySpecifiedType operator()(Name *name)
+        {
+            FullySpecifiedType previousType = switchType(FullySpecifiedType());
+            accept(name);
+            return switchType(previousType);
+        }
+
+    protected:
+        Control *control() const
+        { return q->control(); }
+
+        int findSubstitution(Identifier *id) const
+        { return q->findSubstitution(id); }
+
+        FullySpecifiedType applySubstitution(int index) const
+        { return q->applySubstitution(index); }
+
+        FullySpecifiedType switchType(const FullySpecifiedType &type)
+        {
+            FullySpecifiedType previousType = _type;
+            _type = type;
+            return previousType;
+        }
+
+        virtual void visit(NameId *name)
+        {
+            int index = findSubstitution(name->identifier());
+
+            if (index != -1)
+                _type = applySubstitution(index);
+
+            else
+                _type = control()->namedType(name);
+        }
+
+        virtual void visit(TemplateNameId *name)
+        {
+            QVarLengthArray<FullySpecifiedType, 8> arguments(name->templateArgumentCount());
+            for (unsigned i = 0; i < name->templateArgumentCount(); ++i) {
+                FullySpecifiedType argTy = name->templateArgumentAt(i);
+                arguments[i] = q->operator ()(argTy);
+            }
+
+            TemplateNameId *templId = control()->templateNameId(name->identifier(), arguments.data(), arguments.size());
+            _type = control()->namedType(templId);
+        }
+
+        virtual void visit(QualifiedNameId *name)
+        {
+            QVarLengthArray<Name *, 8> names(name->nameCount());
+            for (unsigned i = 0; i < name->nameCount(); ++i) {
+                Name *n = name->nameAt(i);
+
+                if (TemplateNameId *templId = n->asTemplateNameId()) {
+                    QVarLengthArray<FullySpecifiedType, 8> arguments(templId->templateArgumentCount());
+                    for (unsigned templateArgIndex = 0; templateArgIndex < templId->templateArgumentCount(); ++templateArgIndex) {
+                        FullySpecifiedType argTy = templId->templateArgumentAt(templateArgIndex);
+                        arguments[templateArgIndex] = q->operator ()(argTy);
+                    }
+
+                    n = control()->templateNameId(templId->identifier(), arguments.data(), arguments.size());
+                }
+
+                names[i] = n;
+            }
+
+            QualifiedNameId *q = control()->qualifiedNameId(names.data(), names.size(), name->isGlobal());
+            _type = control()->namedType(q);
+        }
+
+        virtual void visit(DestructorNameId *name)
+        {
+            Overview oo;
+            qWarning() << "ignored name:" << oo(name);
+        }
+
+        virtual void visit(OperatorNameId *name)
+        {
+            Overview oo;
+            qWarning() << "ignored name:" << oo(name);
+        }
+
+        virtual void visit(ConversionNameId *name)
+        {
+            Overview oo;
+            qWarning() << "ignored name:" << oo(name);
+        }
+
+        virtual void visit(SelectorNameId *name)
+        {
+            Overview oo;
+            qWarning() << "ignored name:" << oo(name);
+        }
+
+    private:
+        ApplySubstitution *q;
+        FullySpecifiedType _type;
+    };
+
+public: // attributes
+    LookupContext context;
+    GenTemplateInstance::Substitution substitution;
+
+private:
+    ApplyToType applyToType;
+    ApplyToName applyToName;
+};
+
+ApplySubstitution::ApplySubstitution(const LookupContext &context, const GenTemplateInstance::Substitution &substitution)
+    : context(context), substitution(substitution), applyToType(this), applyToName(this)
+{ }
 
-FullySpecifiedType GenTemplateInstance::subst(Name *name)
+ApplySubstitution::~ApplySubstitution()
 {
-    if (TemplateNameId *t = name->asTemplateNameId()) {
-        QVarLengthArray<FullySpecifiedType, 8> args(t->templateArgumentCount());
+}
 
-        for (unsigned i = 0; i < t->templateArgumentCount(); ++i)
-            args[i] = subst(t->templateArgumentAt(i));
+FullySpecifiedType ApplySubstitution::operator()(Name *name)
+{ return applyToName(name); }
 
-        TemplateNameId *n = _control->templateNameId(t->identifier(),
-                                                     args.data(), args.size());
+FullySpecifiedType ApplySubstitution::operator()(const FullySpecifiedType &type)
+{ return applyToType(type); }
 
-        return FullySpecifiedType(_control->namedType(n));
-    } else if (name->isQualifiedNameId()) {
-        // ### implement me
-    }
+int ApplySubstitution::findSubstitution(Identifier *id) const
+{
+    Q_ASSERT(id != 0);
 
-    for (int i = 0; i < _substitution.size(); ++i) {
-        const QPair<Name *, FullySpecifiedType> s = _substitution.at(i);
-        if (name->isEqualTo(s.first))
-            return s.second;
-    }
+    for (int index = 0; index < substitution.size(); ++index) {
+        QPair<Identifier *, FullySpecifiedType> s = substitution.at(index);
 
-    return FullySpecifiedType(_control->namedType(name));
-}
+        if (id->isEqualTo(s.first))
+            return index;
+    }
 
-FullySpecifiedType GenTemplateInstance::subst(const FullySpecifiedType &ty)
-{
-    FullySpecifiedType previousType = switchType(ty);
-    TypeVisitor::accept(ty.type());
-    return switchType(previousType);
+    return -1;
 }
 
-FullySpecifiedType GenTemplateInstance::switchType(const FullySpecifiedType &type)
+FullySpecifiedType ApplySubstitution::applySubstitution(int index) const
 {
-    FullySpecifiedType previousType = _type;
-    _type = type;
-    return previousType;
-}
+    Q_ASSERT(index != -1);
+    Q_ASSERT(index < substitution.size());
 
-// types
-void GenTemplateInstance::visit(PointerToMemberType * /*ty*/)
-{
-    Q_ASSERT(false);
+    return substitution.at(index).second;
 }
 
-void GenTemplateInstance::visit(PointerType *ty)
-{
-    FullySpecifiedType elementType = subst(ty->elementType());
-    _type.setType(_control->pointerType(elementType));
-}
+} // end of anonymous namespace
 
-void GenTemplateInstance::visit(ReferenceType *ty)
-{
-    FullySpecifiedType elementType = subst(ty->elementType());
-    _type.setType(_control->referenceType(elementType));
-}
+GenTemplateInstance::GenTemplateInstance(const LookupContext &context, const Substitution &substitution)
+    : _symbol(0),
+      _context(context),
+      _substitution(substitution)
+{ }
 
-void GenTemplateInstance::visit(ArrayType *ty)
+FullySpecifiedType GenTemplateInstance::operator()(Symbol *symbol)
 {
-    FullySpecifiedType elementType = subst(ty->elementType());
-    _type.setType(_control->arrayType(elementType, ty->size()));
+    ApplySubstitution o(_context, _substitution);
+    return o(symbol->type());
 }
 
-void GenTemplateInstance::visit(NamedType *ty)
-{
-    Name *name = ty->name();
-    _type.setType(subst(name).type());
-}
+Control *GenTemplateInstance::control() const
+{ return _context.control(); }
 
-void GenTemplateInstance::visit(Function *ty)
+int GenTemplateInstance::findSubstitution(Identifier *id) const
 {
-    Name *name = ty->name();
-    FullySpecifiedType returnType = subst(ty->returnType());
-
-    Function *fun = _control->newFunction(0, name);
-    fun->setScope(ty->scope());
-    fun->setConst(ty->isConst());
-    fun->setVolatile(ty->isVolatile());
-    fun->setReturnType(returnType);
-    for (unsigned i = 0; i < ty->argumentCount(); ++i) {
-        Symbol *arg = ty->argumentAt(i);
-        FullySpecifiedType argTy = subst(arg->type());
-        Argument *newArg = _control->newArgument(0, arg->name());
-        newArg->setType(argTy);
-        fun->arguments()->enterSymbol(newArg);
-    }
-    _type.setType(fun);
-}
-
-void GenTemplateInstance::visit(VoidType *)
-{ /* nothing to do*/ }
-
-void GenTemplateInstance::visit(IntegerType *)
-{ /* nothing to do*/ }
-
-void GenTemplateInstance::visit(FloatType *)
-{ /* nothing to do*/ }
+    int index = 0;
 
-void GenTemplateInstance::visit(Namespace *)
-{ Q_ASSERT(false); }
+    for (; index < _substitution.size(); ++index) {
+        const QPair<Identifier *, FullySpecifiedType> s = _substitution.at(index);
 
-void GenTemplateInstance::visit(Class *)
-{ Q_ASSERT(false); }
-
-void GenTemplateInstance::visit(Enum *)
-{ Q_ASSERT(false); }
-
-// names
-void GenTemplateInstance::visit(NameId *)
-{ Q_ASSERT(false); }
-
-void GenTemplateInstance::visit(TemplateNameId *)
-{ Q_ASSERT(false); }
-
-void GenTemplateInstance::visit(DestructorNameId *)
-{ Q_ASSERT(false); }
-
-void GenTemplateInstance::visit(OperatorNameId *)
-{ Q_ASSERT(false); }
-
-void GenTemplateInstance::visit(ConversionNameId *)
-{ Q_ASSERT(false); }
-
-void GenTemplateInstance::visit(QualifiedNameId *)
-{ Q_ASSERT(false); }
+        if (id->isEqualTo(s.first))
+            break;
+    }
 
+    return index;
+}
diff --git a/src/libs/cplusplus/GenTemplateInstance.h b/src/libs/cplusplus/GenTemplateInstance.h
index a4845f8bc3d151ce8e6adc5e17a7be7be0b8ae06..0d1a8879032dfe015f0c5c92cd236ce8e01e7da4 100644
--- a/src/libs/cplusplus/GenTemplateInstance.h
+++ b/src/libs/cplusplus/GenTemplateInstance.h
@@ -5,51 +5,29 @@
 #include <NameVisitor.h>
 #include <FullySpecifiedType.h>
 
+#include "LookupContext.h"
+
 #include <QtCore/QList>
 #include <QtCore/QPair>
 
 namespace CPlusPlus {
 
-class CPLUSPLUS_EXPORT GenTemplateInstance: protected TypeVisitor, protected NameVisitor
+class CPLUSPLUS_EXPORT GenTemplateInstance
 {
 public:
-    typedef QList< QPair<Name *, FullySpecifiedType> > Substitution;
+    typedef QList< QPair<Identifier *, FullySpecifiedType> > Substitution;
 
 public:
-    GenTemplateInstance(Control *control, const Substitution &substitution);
-
-    FullySpecifiedType operator()(const FullySpecifiedType &ty);
-
-protected:
-    FullySpecifiedType subst(Name *name);
-    FullySpecifiedType subst(const FullySpecifiedType &ty);
-
-    FullySpecifiedType switchType(const FullySpecifiedType &type);
-
-    virtual void visit(PointerToMemberType * /*ty*/);
-    virtual void visit(PointerType *ty);
-    virtual void visit(ReferenceType *ty);
-    virtual void visit(ArrayType *ty);
-    virtual void visit(NamedType *ty);
-    virtual void visit(Function *ty);
-    virtual void visit(VoidType *);
-    virtual void visit(IntegerType *);
-    virtual void visit(FloatType *);
-    virtual void visit(Namespace *);
-    virtual void visit(Class *);
-    virtual void visit(Enum *);
-
-    // names
-    virtual void visit(NameId *);
-    virtual void visit(TemplateNameId *);
-    virtual void visit(DestructorNameId *);
-    virtual void visit(OperatorNameId *);
-    virtual void visit(ConversionNameId *);
-    virtual void visit(QualifiedNameId *);
+    GenTemplateInstance(const LookupContext &context, const Substitution &substitution);
+
+    FullySpecifiedType operator()(Symbol *symbol);
+
+    Control *control() const;
+    int findSubstitution(Identifier *id) const;
 
 private:
-    Control *_control;
-    FullySpecifiedType _type;
+    Symbol *_symbol;
+    LookupContext _context;
     const Substitution _substitution;
 };
 
diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp
index ef8b11ccb1a026d0646352e74abaa2868d63e1da..4d3ed932759f5dee2d490a7c33bd38ce71daaf0a 100644
--- a/src/libs/cplusplus/LookupContext.cpp
+++ b/src/libs/cplusplus/LookupContext.cpp
@@ -347,8 +347,10 @@ QList<Scope *> LookupContext::buildVisibleScopes()
 }
 
 QList<Scope *> LookupContext::visibleScopes(const QPair<FullySpecifiedType, Symbol *> &result) const
+{ return visibleScopes(result.second); }
+
+QList<Scope *> LookupContext::visibleScopes(Symbol *symbol) const
 {
-    Symbol *symbol = result.second;
     QList<Scope *> scopes;
     for (Scope *scope = symbol->scope(); scope; scope = scope->enclosingScope())
         scopes.append(scope);
diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h
index 5424da869ca4efda055195d5762a6dd68beced9f..e9d84c83aeccd1fe8f7a053134ed2d222cb03c7d 100644
--- a/src/libs/cplusplus/LookupContext.h
+++ b/src/libs/cplusplus/LookupContext.h
@@ -98,6 +98,7 @@ public:
     QList<Scope *> visibleScopes() const
     { return _visibleScopes; }
 
+    QList<Scope *> visibleScopes(Symbol *symbol) const;
     QList<Scope *> visibleScopes(const QPair<FullySpecifiedType, Symbol *> &result) const;
 
     QList<Scope *> expand(const QList<Scope *> &scopes) const;
diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp
index f89c2c9afd5bb0c0c3c6a5f905e51e1f5e384282..43694659a5d6688720b92f4fbb46b9cceffc2c3d 100644
--- a/src/libs/cplusplus/ResolveExpression.cpp
+++ b/src/libs/cplusplus/ResolveExpression.cpp
@@ -695,7 +695,7 @@ ResolveExpression::resolveMember(Name *memberName, Class *klass,
     QList<Scope *> scopes;
     _context.expand(klass->members(), _context.visibleScopes(), &scopes);
 
-    QList<Symbol *> candidates = _context.resolve(memberName, scopes);
+    const QList<Symbol *> candidates = _context.resolve(memberName, scopes);
 
     foreach (Symbol *candidate, candidates) {
         FullySpecifiedType ty = candidate->type();
@@ -710,13 +710,17 @@ ResolveExpression::resolveMember(Name *memberName, Class *klass,
             for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) {
                 FullySpecifiedType templArgTy = templId->templateArgumentAt(i);
                 
-                if (i < klass->templateParameterCount())
-                    subst.append(qMakePair(klass->templateParameterAt(i)->name(),
-                                           templArgTy));
+                if (i < klass->templateParameterCount()) {
+                    Name *templArgName = klass->templateParameterAt(i)->name();
+                    if (templArgName && templArgName->identifier()) {
+                        Identifier *templArgId = templArgName->identifier();
+                        subst.append(qMakePair(templArgId, templArgTy));
+                    }
+                }
             }
             
-            GenTemplateInstance inst(control(), subst);
-            ty = inst(ty);
+            GenTemplateInstance inst(_context, subst);
+            ty = inst(candidate);
         }
         
         results.append(Result(ty, candidate));
diff --git a/tests/auto/cplusplus/semantic/tst_semantic.cpp b/tests/auto/cplusplus/semantic/tst_semantic.cpp
index 827a227f053db188aa0c4f2505f4d9ba2a7f193f..6da954ae92fceceeed6bd2c676c7c12a806ebdf2 100644
--- a/tests/auto/cplusplus/semantic/tst_semantic.cpp
+++ b/tests/auto/cplusplus/semantic/tst_semantic.cpp
@@ -408,12 +408,12 @@ void tst_Semantic::template_instance_1()
     QVERIFY(decl);
 
     GenTemplateInstance::Substitution subst;
-    Name *nameTp = control.nameId(control.findOrInsertIdentifier("_Tp"));
+    Identifier *nameTp = control.findOrInsertIdentifier("_Tp");
     FullySpecifiedType intTy(control.integerType(IntegerType::Int));
     subst.append(qMakePair(nameTp, intTy));
 
     GenTemplateInstance inst(&control, subst);
-    FullySpecifiedType genTy = inst(decl->type());
+    FullySpecifiedType genTy = inst(decl);
 
     Overview oo;
     oo.setShowReturnTypes(true);