3

I've been developing some DLL utility projects to avoid having to repeat code throughout other projects, and also for features, algorithms and tests I haven't tried yet. One of those projects is in C++/CLI, language which I'm still learning, so this question may sound stupid. As I have Library Projects in C++/CLI, F# and C#, I use a C# console application to test them. It wasn't working with the C++/CLI Project, so I created a C++/CLI console test project. It never worked, and when I changed the name of the original DLL C++, the references weren't updated. When I (eventually) found out the problem, I changed the .vcxproj file, making the using directives possible, as for one method, but not for the template class Apont<typename T>, which is some kind of interior pointer, but that unlike the .NET type System::IntPtr, uses a value of the type T* instead of void*.

I also found out (from a post in this site) that I must use inside the project what I want to use outside, otherwise that stuff want be emitted in the metadata. So I have a useless static method in a static utility for that purpose:

static void Funcionalidades()
{
    int i = 10;

    Apont<int> a2 = Apont<int>(i);            // stack
    Apont<int> ^a3 = gcnew Apont<int>(i);     // heap CLR

}

Nonetheless, it doesn't work. Here is my main method in the C++/CLI test project:

int main(array<System::String ^> ^args)
{
    int y(10);
    Apont<int> a = Apont<int>(y);

    Console::ReadKey();
    return 0;
}

And below are the errors (I know it can compile with intellisense errors, but I'll show them anyway):

error C2065: 'Apont' : undeclared identifier
error C2062: type 'int' unexpected
IntelliSense: identifier "Apont" is undefined
IntelliSense: type name is not allowed
IntelliSense: expected an expression

Why are these errors here? How can I correct them?

I'd appreciate any answer or reply.

EDIT (clarifications):

  • These errors DO NOT occur on the Funcionalidades method, that is in the DLL project, but on the main method, that is outside the DLL, in the test project.
  • I'm writing everything in the header file; I mean not every header file has a respective .cpp file, although all headers are included in at least one .cpp file.
  • More about Apont:
    • Apont is a template (because T* is used inside and "indirections on a generic type paremeter are not allowed").
    • Apont has a copy constructor, so Apont<int> a = Apont<int>(someInt) should work;
    • Apont<int> a(someInt) doesn't work;
    • Apont is some kind of interior pointer; and I didn't post the whole code because it isn't relevant, I'd have to translate varibles' names, and it may have errors I can easily fixed by me, but that would only distract you.

NTH EDIT (where 'n' is a number I don't know):

Apont's code you've been complaining about for so long:

    template<typename T> public ref class Apont sealed : public IDisposable
    {
        bool eliminado;
        T *pointer;

        /*void Dispose(bool tudo)
        {
            if (!eliminado)
            {
                if (tudo)
                {
                    ~Apont();
                }
                else
                {
                    !Apont();
                }
            }
        }*/
        !Apont() // finalizador: limpa os recursos "unmanaged"
        {
            delete pointer;
            pointer = nullptr;
            eliminado = true;
        }

    public:
        Apont(T &valor)
        {
            pointer = &valor;
            eliminado = false;
            ErroSeNulo = false;
            ErroSeEliminado = true;
        }
        Apont(T &valor, bool erroSeEliminado, bool erroSeNulo)
        {
            pointer = &valor;
            eliminado = false;
            ErroSeEliminado = erroSeEliminado;
            ErroSeNulo = erroSeNulo;
        }
        Apont(Apont<T> %outroApont)
        {
            this->pointer = &outroApont
        }

        property bool ErroSeEliminado;
        property bool ErroSeNulo;
        property T Valor
        {
            T get()
            {
                if (pointer != nullptr)             
                    return *pointer;
                else if (eliminado && ErroSeEliminado)
                    throw gcnew ObjectDisposedException("O objeto já foi pelo menos parcialmente eliminadao.");
                else if (ErroSeNulo)
                    throw gcnew NullReferenceException();
                else
                    return 0;
            }
        }

        /*
        Apont operator ~(/*T valor* /)
        {
            // este operador tem de ser declarado fora desta classe 
        }*/
        T operator !(/*Apont apont*/)
        {
            return Valor;
        }
        void operator =(Apont<T> outroApont)
        {
            pointer = outroApont;
            ErroSeEliminado = outroApont.ErroSeEliminado;
            ErroSeNulo = outroApont.ErroSeNulo;             
        }
        template<typename U> void operator =(Apont<U> outroApont)
        {
            pointer = safe_cast<T>(outroApont.pointer);
            ErroSeEliminado = safe_cast<T>(outroApont.ErroSeEliminado);
            ErroSeNulo = safe_cast<T>(outroApont.ErroSeNulo);
        }
        /*
        void operator =(T *&outroPointer)
        {
            pointer = outroPointer;
        }
        template<typename U> void operator =(U *&outroPointer)
        {
            pointer = safe_cast<T>(outroPointer);
        }*/
        void operator =(T *outroPointer)
        {
            pointer = outroPointer;
        }
        template<typename U> void operator =(U *outroPointer)
        {
            pointer = safe_cast<T>(outroPointer);
        }


        ~Apont() // destruidor: limpa todos os recursos
        {               
            this->!Apont();
        }

        // Error C2605: 'Dispose': this method is reserved within a managed class
        // O código será gerado automaticamente a partir do finalizador e do destrutor
    };

    template<typename T> Apont<T> operator ~(T &valor)
    {
        return gcnew Apont<T>(valor);
    }
14
  • 1
    You should probably make a short, self-contained, correct example. Too many things missing or not stated in your question that would be necessary for an answer. I am sure you will get more replies if you follow the suggestions in the link above. Commented Mar 27, 2013 at 17:39
  • 1
    The function names/signatures may be mangled in c++ when compiled even to dll, you will need to find what they are in the dll and create links to them for example uncover the internal name from the dll via use of link /dump /exports mydll.dll. Check that the values and functions you expect to be present are actually present in your dll with the link command I mentioned before. Let me know how you get on and I will try and help you to get this resolved. Commented Apr 16, 2013 at 9:57
  • 1
    Hi, yep you use it from the command line. id suggest navigating into the directory the dll is in and just using link /dump/exports mydll.dll rather than having to type the full path after the command:) Commented Apr 17, 2013 at 9:28
  • 1
    I see, Just noticed some of my dlls are doing the same as well and had to turn off debug info ` Properties, Linker, Debugging, Generate Debug Info = No` so the names were not mangled. and were correctly visible. On a sidenote dumpbin.exe does a similar job (VS commandline) or dependency walker has a nice gui to it to achieve the same. I am looking into this hidden function name problem as I have the same issue with some of my own dlls, however the functions are usable in vs when I import the dll...very strange. Commented Apr 18, 2013 at 10:17
  • 1
    Utilidades.ComNativos is the namespace I get looking at the dll, Apont is not exposed at all, however UtilCMM is, perhaps take a look at what differentiates these two classes? (starting point might be: apont is a sealed class, utilscmm is a static class) Commented Apr 18, 2013 at 10:56

5 Answers 5

3
+25

Your error as it appears is usually missing declaration of class. This usually happens then the code in header is header-guarded away.

How does this happened?

If you include Apont header inside Funcionalidades and then include Funcionalidades header in Apont than you're in trouble. That happens because Funcionalidades header is missing declaration of Apont in case you include Apont in your main before including Funcionalidades.

Then you include Apont first time, it will enable header guard. Then it will include Funcionalidades which includes Apont as well. Because header guard is already enabled Funcionalidades header will not have Apont declaration. At the same time Apont declaration didn't even started yet in corresponding header file of Apont. And here you are, can't compile because of this problem in main, because at library compiling you haven't such a dependencies.

How do I fix it?

Move usage of Apont inside Funcionalidades implementation in cpp code, keeping header file without dependencies.

Sign up to request clarification or add additional context in comments.

1 Comment

that seems plausible, but I had already tried to move the implementation of Funcionalidades back and forth, and the place makes utterly no difference. There are also no infinite inter-references, the file that contains Apont doesn't refer the one that contains Funcionalidades. What makes me most angry is this short error without a piece of description of its cause across the projects. And I really though this answer as going to work. +1 for the effort and making me catch some more errors.
1

It just complains that it doesn't know "Apont". I don't know what it is either, you didn't post its code. Just declaring an arbitrary version of it:

generic<typename T>
public ref class Apont {
    T value;
public:
    Apont(T init) : value(init) {}
};

static void Funcionalidades()
{
    int i = 10;

    Apont<int> a2(i);                      // stack
    Apont<int> ^a3 = gcnew Apont<int>(i);  // heap CLR

}

Note the altered code for "a2", avoid copy constructors for reference types. Again in main:

    Apont<int> a(y);

7 Comments

I didn't include Apont's code because I don't think it is relevant, and it is also likely to be filled with stupid errors I can solve on my own. Still, if you feel I should provide it, please ask below and I'll edit my post and insert it.
Apont is suppose to be some kind of interior pointer (only with an inside value of type T* instead of void*). Your version is some kind of wrapper.
Oddly enough, your version isn't working either! The errors are EXACLY the same!
I posted tested code, it compiles fine. Read the last paragraph of the answer.
I do not doubt it. I read the last paragraph, and did exacly what you said. I even (actually, I had already done) defined a copy constructor. It must be some problem in the project settings. Why is this happening? What should I do?
|
1

I must use inside the project what I want to use outside

If this is true, have you called the static function anywhere? Chances are the uncalled function might get optimized out.

1 Comment

that actually makes sense, but as the purpose of this function is to make other stuff available, if I had a function to make this one available, I'd need to have one more function for each function I had, that is, an infinite number of functions. The only way would be to do this in A Console project, where the main function is always called, as all the functions in it (unless there's some exception in the middle). However, how come are there C++ DLL's, if there's no main function to be called? Either you're wrong, or my compiler has a problem.
1

Could it be missing using statement for namespaces? Make sure you have the right using statement at your main method. Also make sure you have added a reference such that the project containing the main method references the project containing Apont.

1 Comment

thanks for the reply, but I already checked it all at least 5 separate times before posting this question, and 5 more afterwords.
1

Sorry for taking so long to get back to you: I have a couple of points for you that should help to sort the problem out. - the template class is declared as sealed: this means you cant use it as a base class (opposite of your main reason for a templated class). At the very least its not needed so it may be worth removing. - secondly, and more importantly, in C++ templates are evaluated at compilation time, so, as you have no specified instances declared theres no evaluation of Apont and its not compiled into the DLL. To enable specific versions of the template class you can, at the end of the UtilCMM.h file, add the following:

  • class template Apont<int>;
  • class template Apont<float>;
  • class template Apont<double>;

This is due to the fact that in C++ templates are expanded by the preprocessor at compile time, much like macros, however only version which are explicitly used are processed at compilation time: this is a great strength and weakness both. The solution as I have always found (in consensus with other C++ programmers) has been to either:

  • explicitly instanciate the versions you need to export in the dll
  • provide a header file with the template, which can then be utilised by who-ever you are distributing the code to

If there are other ways to achieve the same, I have not yet encountered them, and would love to find out, alas these are the limitations of templates.

then when you compile you should have the three specific versions available. Just add more for each type you wish to include in the DLL. Sorry I didn't spot this earlier, they both leaped out when I saw the full code, Now if I can just get the project to compile I can try the changes myself (my version of VS does not load your version of vcproj files, typical).

2 Comments

I used ref class template Apont<int>, but unfortunately the errors remained in the test project. As I was tired of this I merged the DLL with the test project and it worked. I'll continue to try to fix it (I kept the original projects) and see if the merging actually changes something (I now have the "Dependency Walker" so I can see the emitted metadata). +1 for all the help, I'll try be back as soon as possible to the matter.
Anyway, I wanted Apont to be a template. That would be like having three classes for three types.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.