Search code examples
c++linkerextern

How to solve this undeclared identifier


I'm getting an undeclared identifier error (C2065 on vs2013) on my project, I managed to replicate the problem in the example code below:

foo.h:

#pragma once

#include "bar.h"

class Foo
{

public:
    inline void doStuff() { someFunction(); }

};

bar.h:

#pragma once

#include <map>

#include "foo.h"

extern std::map<const char*, Foo> myMap;

void someFunction();

bar.cpp:

#include "bar.h"

std::map<const char*, Foo> myMap;

void someFunction()
{

}

main.cpp:

#include "foo.h"

int main()
{
    Foo foo;
    foo.doStuff();
    return 0;
}

When building on Visual Studio Express 2013, it gives these errors:

error C2065: 'Foo' : undeclared identifier

error C2923: 'std::map' : 'Foo' is not a valid template type argument for parameter '_Ty'

error C3861: 'someFunction': identifier not found

What is the problem here and how can it be solved?


Solution

  • The problem is caused by circular dependency between foo.h and bar.h. It can be resolved using any of the following methods that I can think of.

    Method 1

    1. Use forward declaration of the class Foo in bar.h.
    2. Don't use #include "foo.h" in bar.h.

    foo.h:

    #pragma once
    
    #include "bar.h"
    
    class Foo
    {
    
    public:
        inline void doStuff() { someFunction(); }
    
    };
    

    bar.h:

    #pragma once
    
    #include <map>
    
    // #include "foo.h"
    class Foo;
    
    extern std::map<const char*, Foo> myMap;
    
    void someFunction();
    

    Method 2

    1. Create foo.cpp and add it to the project.
    2. Move the implementation of Foo::doStuff() to foo.cpp.
    3. Don't use #include "bar.h" in foo.h.

    foo.h:

    #pragma once
    
    class Foo
    {
    
    public:
        void doStuff();
    
    };
    

    bar.h:

    #pragma once
    
    #include <map>
    
    #include "foo.h"
    
    extern std::map<const char*, Foo> myMap;
    
    void someFunction();
    

    foo.cpp:

    #include "foo.h"
    #include "bar.h"
    
    void Foo::doStuff(){ someFunction(); }
    

    Method 3

    Use both Method 1 and Method 2.

    foo.h:

    #pragma once
    
    class Foo
    {
    
    public:
        void doStuff();
    
    };
    

    bar.h:

    #pragma once
    
    #include <map>
    
    // #include "foo.h"
    class Foo;
    
    extern std::map<const char*, Foo> myMap;
    
    void someFunction();
    

    foo.cpp:

    #include "foo.h"
    #include "bar.h"
    
    void Foo::doStuff(){ someFunction(); }
    

    I strongly suggest using Method 3. As a general guide, it's better to use forward declarations in header files if you don't need the full definition of a class.