0

I have a project with quite a lot of function templates that I wrote back in Visual Studio 2017, and it always worked fine. Now I have to build it in VS2019, because I need to include the lib in another project that is written in VS2019, and the thing won't build.

There is one function template it seems to take issue with, although it doesn't actually complain about the function itself. The compiler just says "identifier not found" when I invoke it in the code. The thing is there in the namespace, however, even InteliSense sees it and links to it without complaining. Just the compiler won't.

Here's the code in question:

// declaration

namespace Oparse
{
    // lots of other functions, many of them templates
    template <typename T> OpModel<T> *_ModelPtr(T *receiver) { return new OpModel<T>(receiver); };
}


// Invocation

namespace Oparse
{

        template <class T, class U>
    class OpModelFactory
        : public OpNestable
    {
        public:
        OpModelFactory<T, U>(vector<U*> &receiver) : OpNestable(OP_MODELFACTORY), receiver(receiver) {};
        // other stuff

        void Serialize(string key, stringstream &stream, unsigned int indents)
        {
            
            for (unsigned int i = 0; i < receiver.size(); ++i)
            {
                // check if the instances are really of the type of this OpModel, otherwise there may be duplicates between polymorphic factories populating the same receiver.
                T *currentModel = dynamic_cast<T*>(receiver[i]);
                if (currentModel != NULL)
                {
                    OpModel<T> *parser = _ModelPtr<T>(currentModel);    // <-- identifier not found
                    parser->Serialize(key, stream, indents);
                    delete parser;
                }
            }
        };

        private:
        vector<U*> &receiver;
    }
}

If I comment that invocation, the project builds, despite there being a whole lot more function templates declared right where this one is. I have no clue what to do to make the linker find it. Are there any Visual Studio wizzards who could give me a hint? I must honestly confess that I haven't used the IDE in years, and it's my first time in Visual Studio 2019...

Here's the complete output of the error. There's a second message to it, but I found it perfectly unhelpful:

1>D:\Orbiter_installs\Orbiter2016\Orbitersdk\Oparse\include\OpModel.h(138,27): error C3861: '_ModelPtr': identifier not found
1>D:\Orbiter_installs\Orbiter2016\Orbitersdk\Oparse\include\OpModel.h(152): message : see reference to class template instantiation 'Oparse::OpModelFactory<T,U>' being compiled

And no, there's not further message attached. I have seen similar messages that usually go on with "with ... $further information", but this is all I get.

UncleBob
  • 1,233
  • 3
  • 15
  • 33
  • 6
    Probably not the source of your error, but identifiers that start with an underscore followed by an uppercase are reserved for the compiler. –  Jul 26 '21 at 18:22
  • 1
    Expanding on the above (might as well learn all of the related rules): [What are the rules about using an underscore in a C++ identifier?](https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier). – user4581301 Jul 26 '21 at 18:23
  • 4
    I'm also going to venture a wild guess and suspect that you have a circular header dependency. –  Jul 26 '21 at 18:24
  • 1
    Linker error codes start with capital L. Compiler error codes start with capital C. I wonder why is that. Some weird arbitrary kinda rule. – n. m. could be an AI Jul 26 '21 at 19:01
  • embarassingly, I have never even noticed that... but then I don't write that much C++. – UncleBob Jul 26 '21 at 19:13
  • I don't think we can offer much help. The code is not enough for us to remotely debug. – drescherjm Jul 26 '21 at 19:14
  • Well, the entire project is here: https://github.com/TheNewBob/Oparse but there's another dependency required, so I don't expect anyone to go through the trouble. I was hoping that somebody more experienced would spot what was wrong with it, resp. why VS2019 might have a problem where VS2017 didn't. – UncleBob Jul 26 '21 at 19:21
  • 3
    What you can do is copy the project to a fresh place, do a full rebuild, and if the problem persists, start throwing away code, and replacing code you cannot just cut and throw away by simpler code, until you arrive at a [mcve]. – n. m. could be an AI Jul 26 '21 at 19:31
  • 1
    The include strategy of that project is extremely fragile (`OpModel.h` doesn't `#include` anything despite having clear dependencies). Headers requiring that other headers are included before them is the true problem here. Any fix that doesn't address that is just a delay until the next hard-to-track error pops up. –  Jul 26 '21 at 19:33
  • 1
    @Frank Good guess! It is indeed a problem of circular dependency, that can be solved using forward declaration. – prapin Jul 26 '21 at 19:43
  • @Frank yeah, I have a really difficult time managing includes when I *need* to put logic in the header files, which I have to when using templates. As long as I can keep all the actual code in the cpp files, it's a lot easier. – UncleBob Jul 26 '21 at 20:42

1 Answers1

1

There is a circular dependency problem.

In Oparse.h, you first include OpModel.h that requires_ModelPtr in implementation of Serialize , but_ModelPtr is only defined later in the header.

You need to forward declare the template method.

In OpModel.h, write this instead:

namespace Oparse
{
    template<typename T> class OpModel;
    template <typename T> OpModel<T>* _ModelPtr(T* receiver);
    // Remaining of OpModel.h...
    typedef map<string, pair<Oparse::OpValue*, vector<Oparse::OpValidator*>>> OpModelDef;
    typedef vector<pair<Oparse::OpValue*, vector<Oparse::OpValidator*>>> OpValues;
    ...
prapin
  • 6,395
  • 5
  • 26
  • 44
  • Oh wow... just... wow. Thank you so much! How on earth was that *not* a problem when I built in VS 2017?? – UncleBob Jul 26 '21 at 20:36
  • 2
    Small remark: I noticed that your project builds around 3 times faster if you use `OpStdLibs.h` as a precompiled header. – prapin Jul 26 '21 at 21:03