Thread: What's the cause of this error message?

  1. #1
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485

    What's the cause of this error message?

    I get a compile error I can not figure out with this code:

    In the .h file

    Code:
    template <class T> class ABC {
    
        private:
    
            struct node_t {
                T data;
                struct node_t *next;
            };
    
            node_t *new_node(T element);
    };
    In the .cpp file as the first thing after the #includes:

    Code:
    template <class T>
    node_t *ABC<T>::new_node(T element) {
        struct node_t *node = new struct node_t;
        node->data = element;
        node->next = NULL;
        return node;
    }
    Code:
    ABC.cpp:17: error: expected constructor, destructor, or type conversion before ‘*’ token
    The file has about 200 lines of code and this section is the only part that generates an error (for now ).

  2. #2
    Registered User
    Join Date
    May 2010
    Posts
    4,633
    Normally with templates both the declaration and implementation must be in the same compilation unit. Did you try to place the code in the second snippet in the .h file?

    Also you may want to tell us what line in the snippet corresponds to the line 17 of your error message, after all you have several * in your snippet.

    Jim

  3. #3
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by jimblumberg View Post
    Normally with templates both the declaration and implementation must be in the same compilation unit. Did you try to place the code in the second snippet in the .h file?
    It started it's life as a .h file (because I'm lazy), now I have moved the implementation to a .cpp file. There are 12 other functions except this one that all compile without problem, I have added the template <class T> ABC<T>:: bit to all of them in the cpp file.

    Quote Originally Posted by jimblumberg View Post
    Also you may want to tell us what line in the snippet corresponds to the line 17 of your error message, after all you have several * in your snippet.

    Jim
    Sorry, that's line 2 in the second code box above, the node_t *ABC<T> etc. bit. This function returns a pointer, to me it looks ok, but is there some other way I need to do it if templates are involved perhaps?

  4. #4
    Registered User
    Join Date
    May 2010
    Posts
    4,633
    It started it's life as a .h file (because I'm lazy), now I have moved the implementation to a .cpp file.
    Templates require that both the definition and the implementation to be in the same compilation unit.


    Try moving the implementation back into the .h file. Many times a template class is header only, no .cpp file required.

    Jim

  5. #5
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by jimblumberg View Post
    Templates require that both the definition and the implementation to be in the same compilation unit.

    Try moving the implementation back into the .h file. Many times a template class is header only, no .cpp file required.

    Jim
    But what exactly do you consider a single compilation unit? The .h file simply defines the class interface, I thought mixing implementation in the .h file was considered a cardinal sin. I have a pocket reference here that states:

    Member functions defined outside of the template class in which they are declared must be parameterized as well. For example:
    Code:
    template <class Type>
    bool Array<Type>::insert(const Type &element, int pos) {
    ...
    }
    Which is what I have done for all other functions. Those compiles without errors as long as I add the template parameters like above.

  6. #6
    Registered User
    Join Date
    May 2010
    Posts
    4,633
    I thought mixing implementation in the .h file was considered a cardinal sin.
    Not when dealing with templates.
    Member functions defined outside of the template class in which they are declared must be parameterized as well.
    Quite true. Just like member functions of non-template classes defined outside the class must be properly parameterized.

    But what exactly do you consider a single compilation unit?
    Usually a single compilation unit is one file. However you can use multiple files by including the implementation in the include file (after the class definition).

    You may find this link informative Templates C++ Documentation, be sure you scroll down to the bottom of this page and read the section titled: "Templates and multiple-file projects".

    Templates and multiple-file projects
    From the point of view of the compiler, templates are not normal functions or classes. They are compiled on demand, meaning that the code of a template function is not compiled until an instantiation with specific template arguments is required. At that moment, when an instantiation is required, the compiler generates a function specifically for those arguments from the template.

    When projects grow it is usual to split the code of a program in different source code files. In these cases, the interface and implementation are generally separated. Taking a library of functions as example, the interface generally consists of declarations of the prototypes of all the functions that can be called. These are generally declared in a "header file" with a .h extension, and the implementation (the definition of these functions) is in an independent file with c++ code.

    Because templates are compiled when required, this forces a restriction for multi-file projects: the implementation (definition) of a template class or function must be in the same file as its declaration. That means that we cannot separate the interface in a separate header file, and that we must include both interface and implementation in any file that uses the templates.

    Since no code is generated until a template is instantiated when required, compilers are prepared to allow the inclusion more than once of the same template file with both declarations and definitions in a project without generating linkage errors.



    Jim

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Subsonics
    What's the cause of this error message?
    It looks like you use node_t as if it were in the global namespace or in scope, but actually the node_t struct is nested inside ABC, thus you should write:
    Code:
    template <class T>
    typename ABC<T>::node_t *ABC<T>::new_node(T element) {
    Quote Originally Posted by Subsonics
    But what exactly do you consider a single compilation unit?
    A given source file with all headers (and to-be-included-only implementation files) included.

    Quote Originally Posted by Subsonics
    The .h file simply defines the class interface, I thought mixing implementation in the .h file was considered a cardinal sin.
    Exceptions are made for inline functions and for templates (although there are exceptions to this exception as well).
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by laserlight View Post
    It looks like you use node_t as if it were in the global namespace or in scope, but actually the node_t struct is nested inside ABC, thus you should write:
    Code:
    template <class T>
    typename ABC<T>::node_t *ABC<T>::new_node(T element) {
    Thanks, unfortunately that moved the problem on to other errors like:

    error: expected initializer before ‘struct’
    error: expected constructor, destructor, or type conversion before ‘->’ token

    I will try to create a small compilable example that replicates this and get back.

    Quote Originally Posted by laserlight View Post
    Exceptions are made for inline functions and for templates (although there are exceptions to this exception as well).
    That's interesting, but is the idea that it's better to keep it separated (in case of templates) if possible?

    Quote Originally Posted by jimblumberg View Post
    Not when dealing with templates.

    Quite true. Just like member functions of non-template classes defined outside the class must be properly parameterized.


    Usually a single compilation unit is one file. However you can use multiple files by including the implementation in the include file (after the class definition).

    You may find this link informative Templates C++ Documentation, be sure you scroll down to the bottom of this page and read the section titled: "Templates and multiple-file projects".
    Thanks, that's interesting but seemingly at odds with "The C++ programming language" Stroustrup.

    Members of a template class are declared and defined exactly as they would have been for a non-template class. A template member need not be defined within the template class itself. In that case, it's definition must be provided somewhere else, as for non-template class members (§C.13.7). Page 330, 13.2.1
    I may try to just move the offending function to the header, if that helps.

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Subsonics
    That's interesting, but is the idea that it's better to keep it separated (in case of templates) if possible?
    I think that that is a matter of subjective style.

    Quote Originally Posted by Subsonics
    Thanks, that's interesting but seemingly at odds with "The C++ programming language" Stroustrup.
    It isn't: what you quoted does not say anything about whether the definition of the class template's member function should be in the same translation unit or not. What it does say is that it can be separate from the class template's definition, just as the definition of a class' member function can be separate from the class definition.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by laserlight View Post
    I think that that is a matter of subjective style.


    It isn't: what you quoted does not say anything about whether the definition of the class template's member function should be in the same translation unit or not. What it does say is that it can be separate from the class template's definition, just as the definition of a class' member function can be separate from the class definition.
    True, but in contrast to the earlier quote it seems that way imo.

    Because templates are compiled when required, this forces a restriction for multi-file projects: the implementation (definition) of a template class or function must be in the same file as its declaration.

  11. #11
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    I have edited out most of the content of the files and still get the same error, these files should compile afaik.

    ABC.h
    Code:
    #ifndef ABC_H
    #define ABC_H
    
    #include <cstddef>
    
    template <class T> class ABC {
    
        private:
    
            struct node_t {
                T data;
                struct node_t *next;
            };
    
            node_t *new_node(T element);
    
    };
    
    #endif
    .cpp
    Code:
    #include "ABC.h"
    
    //template <class T>
    //typename ABC<T>::node_t *ABC<T>::node_node(T element)
    template <class T>
    node_t *ABC<T>::new_node(T element) {
        struct node_t *node = new struct node_t;
        node->data = element;
        node->next = NULL;
        return node;
    }
    
    int main(void)
    {
        return 0;
    }

  12. #12
    Registered User
    Join Date
    May 2010
    Posts
    4,633
    Since the struct node_t is local to your class it can't be used outside the class. Therefore trying to return this structure from a class member function would be an error.


    Jim

  13. #13
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by jimblumberg View Post
    Since the struct node_t is local to your class it can't be used outside the class. Therefore trying to return this structure from a class member function would be an error.


    Jim
    That makes sense, but the function is never used, and can't be used outside of the class, it's declared as private and is used as a utility function to make implementation less repetitive.

  14. #14
    Registered User
    Join Date
    May 2010
    Posts
    4,633
    but the function is never used
    Then why have it?
    and can't be used outside of the class
    Then you shouldn't need to return the structure.

    The issue really is, "why are you defining the structure inside the class"? It really seems that this structure should be external to the class.

    Jim

  15. #15
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by jimblumberg View Post
    Then why have it?

    Then you shouldn't need to return the structure.
    As I said, it's a utility (helper) function. Declaring it private is roughly equivalent with functions with file scope in C. Think of it this way, every time I need to add a node, I need to create a new instance of that struct, I can do it manually, or by calling this helper function. But never the less, it's internal to the class and part of the implementation.

    Quote Originally Posted by jimblumberg View Post
    The issue really is, "why are you defining the structure inside the class"? It really seems that this structure should be external to the class.

    Jim
    Because the structure is a building block that should not be part of, and hidden from the interface. It's an internal implementation detail.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Help with Error message
    By Holmeslice in forum C Programming
    Replies: 4
    Last Post: 10-07-2012, 03:33 AM
  2. C++ Error message when trying to run
    By Huzapro0 in forum C++ Programming
    Replies: 6
    Last Post: 08-11-2011, 08:45 AM
  3. Replies: 13
    Last Post: 10-08-2010, 05:35 PM
  4. Error message
    By vopo in forum Windows Programming
    Replies: 5
    Last Post: 10-03-2007, 03:11 AM
  5. Need help with error message!
    By smokedragon in forum C++ Programming
    Replies: 5
    Last Post: 04-04-2002, 09:33 PM