Search code examples
c++11templatesvisual-studio-2017inline

VS 2017 crashes when compiling template implementation


To make it short visual studio 2017 crashes when I am compiling this file:

#pragma once

/// @file
/// @brief Class mbe::HandleBase

#include <unordered_map>
//#include <cassert>

namespace mbe
{
    template <class Derived>
    class HandleBased abstract
    {
    public:
        typedef unsigned long long int HandleID;

    public:
        HandleBased();
        ~HandleBased();

        // Maybe rename to GetHandleId()?
        HandleID ThisHandleId();
        /*{
            return id;
        }*/

        // Maybe rename to FindHandledObject
        static Derived * FindPtr(HandleID id)
        {
            auto it = HandleBased::GetMap().find(id);
            if (it == HandleBased::GetMap().end())
                return nullptr;

            // Should always be save
            //assert(dynamic_cast<Derived *>(it->second));
            return static_cast<Derived *>(it->second);
        }

    private:
        static HandleID NextHandle()
        {
            // Every handle will get its own unique id
            static HandleID next = 0;
            return next++;
        }

        static std::unordered_map<HandleID, HandleBased *>& GetMap()
        {
            // Create the static map which will be used to keep track of the Derived handles and their ids
            static std::unordered_map<HandleID, HandleBased *> map;
            return map;
        }

    private:
        HandleID id; // The id of this handle object
    };

#pragma region Template Implementation

    template<class Derived>
    HandleBased<Derived>::HandleBased() :
        id(NextHandle())
    {
        HandleBased::GetMap()[id] = this;
    }

    template<class Derived>
    HandleBased<Derived>::~HandleBased()
    {
        auto it = HandleBased::GetMap().find(id);
        HandleBased::GetMap().erase(it);
    }

    template<class Derived>
    inline HandleID HandleBased<Derived>::ThisHandleId()
    {
        return id;
    }

#pragma endregion

} // namespace mbe

It compiles fine when the ThisHandleId() function is defined directly below its definition. Is something wrong with my template implementation? I have noticed that the HandleID typedef does not show up in intellisense.

Sometimes VS crashes completely (goes grey and windows displays the message: "Visual Studio 2017 stopped working". Sometimes it just shows that ingame message: "C/C++ optimising compiler stopped working"

enter image description here

Furthermore, I get a ton of compile errors when defining the other functions beneath the HandleBase class or in an inline file. As I said, everything compiles just fine if all functions are implemented just beneath their definition. I have also experimented with removing inline which avoids the crash but gives me even more compile errors. Mosty complete non-sense such as:


2>c:\users\adrian\documents\visual studio 2017\projects\mars base engine ecs 5\mars base engine ecs\handlebase.h(75): warning C4346: "ThisHandleId": Abhängiger Name ist kein Typ

2>c:\users\adrian\documents\visual studio 2017\projects\mars base engine ecs 5\mars base engine ecs\handlebase.h(76): note: Präfix mit "typename" zum Angeben eines Typs

2>c:\users\adrian\documents\visual studio 2017\projects\mars base engine ecs 5\mars base engine ecs\handlebase.h(76): error C2988: Unerkannte Vorlagendeklaration/-definition

2>c:\users\adrian\documents\visual studio 2017\projects\mars base engine ecs 5\mars base engine ecs\handlebase.h(76): error C2059: Syntaxfehler: ""

2>c:\users\adrian\documents\visual studio 2017\projects\mars base engine ecs 5\mars base engine ecs\handlebase.h(76): error C2143: Syntaxfehler: Es fehlt ";" vor "{"

2>c:\users\adrian\documents\visual studio 2017\projects\mars base engine ecs 5\mars base engine ecs\handlebase.h(76): error C2447: "{": Funktionsheader fehlt - Parameterliste im alten Stil?


Sorry for the German comments, but u can probably guess what some of them meen. There is stuff like 'depended name is not a type', 'syntax error ""' and 'missing an ; before {'

Also, I don't think removing the inline is a good idea in the first place.

In case you are wondering what the code is for, its described in the acceted answer of this stack overflow question: Using shared_ptr for unique ownership (kind of) - is this good practice?

Hope you can help me with this weird occurence....

Thanks, Adrian


Solution

  • HandleID is a scoped type. Hence, you will need to use HandleBased<Derived>::HandleID. Furthermore, since HandleID is a dependent type. Hence, you will need to use typename HandleBased<Derived>::HandleID.

    Use:

    template<class Derived>
    inline typename HandleBased<Derived>::HandleID HandleBased<Derived>::ThisHandleId()
    {
        return id;
    }
    

    Alternatively, use trailing return type (Thanks are due to @Angew):

    template <class Derived>
    auto HandleBase<Derived>::ThisHandleId() -> HandleId
    {
       return id;
    }
    

    That works since trailing return types are within the scope of the class.