Thread: Typedef declaration and header files

  1. #1
    Registered User
    Join Date
    May 2008
    Posts
    106

    Typedef declaration and header files

    Hi,

    Where should I put typedef that is used in several header files? Putting it in each file causes multiple declaration error, and yet each header file requires a declaration. Should I play around with name spaces?

    Thx

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    27,183
    Place it in a header that is included by the other headers; remember to use inclusion guards.
    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

  3. #3
    Informer -Adrian's Avatar
    Join Date
    Jan 2013
    Posts
    814
    And post your code if you still run into issues.
    Last edited by -Adrian; 10-11-2019 at 06:05 AM. Reason: too slow ;)

  4. #4
    Registered User
    Join Date
    May 2008
    Posts
    106
    Yes, this works if I put implementations in the header, but i would like to have a clean header file and a cpp file with function bodies. The below pattern currently produces an mt19937 error:

    So the header would read (without guards, for brevity):

    Code:
    #include <random>
    #include <vector>
    
    typedef std::mt19937 rngT;
    rngT rng;
    
    const std::vector<int> Roll_DX_Ntimes(rngT& r, const int X, const int N);
    Let the header be called dice.h. I have this in dice.cpp:

    Code:
    #include <random>
    #include <vector>
    #include "dice.h"
    
    const std::vector<int> Roll_DX_Ntimes(rngT& r, const int X, const int N) {
    // implementation
    }
    and in the main

    Code:
    #include <random>
    #include <vector>
    #include "dice.h"

  5. #5
    Informer -Adrian's Avatar
    Join Date
    Jan 2013
    Posts
    814
    You're initializing an object in the header. That is the problem, not the typedef.
    Code:
    #include <random>
    #include <vector>
    
    typedef std::mt19937 rngT;
    rngT rng; // ← this is the issue
    
    const std::vector<int> Roll_DX_Ntimes(rngT& r, const int X, const int N);
    Last edited by -Adrian; 10-11-2019 at 08:38 AM. Reason: formatting

  6. #6
    Registered User
    Join Date
    May 2008
    Posts
    106
    OK, I missed that! So where should the second line go, given that the type is used in practically the whole program, i.e. certainly downstream of dice.h. Does it need to stay global?

  7. #7
    Informer -Adrian's Avatar
    Join Date
    Jan 2013
    Posts
    814
    Put it as close to your use as is sensible, e.g.
    Code:
    int main()
    {
        rngT rng;
        const auto result = Roll_DX_Ntimes(rng, 1, 2);
    }
    Avoid global variables except for edge cases (which are rare).

    Edit: If you want to share the rng, see if passing it to the call chain in main is feasible. If you think you cannot avoid it, then do:
    Code:
    // dice.h
    extern rngT rng;
    
    // dice.cpp
    rngT rng;
    Last edited by -Adrian; 10-11-2019 at 09:10 AM. Reason: f*** this slow forum

  8. #8
    Registered User
    Join Date
    Aug 2019
    Location
    Inside a Singularity
    Posts
    118
    You could use
    Code:
    #pragma once
    for your header file containing your typedefs, function declarations and definitions, etc and then include in multiple files without any problems I believe.

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    27,183
    Quote Originally Posted by serge
    i would like to have a clean header file and a cpp file with function bodies.
    You should be aware that as there is increasing support for templates and declaring stuff to be inline, it has also become more common for libraries (and hence C++ programs in general) to become "header-only", as in containing template classes/functions and inline functions and even inline variables defined in headers, with a much smaller amount of code going into source files.

    Quote Originally Posted by Zeus_
    You could use
    Code:
    #pragma once
    for your header file containing your typedefs, function declarations and definitions, etc and then include in multiple files without any problems I believe.
    Yes, you could, but no, you shouldn't. #pragma once is non-standard (which admittedly is a feature of #pragma: a standard way to enable non-standard stuff), and while compilers tend to support it these days, there's no guarantee that it will do the right thing on all compilers for the various ways C++ source code could be stored and compiled on file systems. On the other hand, inclusion guards will always do the right thing... as long as they are unique (hence techniques like including a timestamp in the inclusion guard name). Eventually we may see both of them phased out should modules become a reality in C++20 and continue to see adoption after that.

    In this case though, neither a header inclusion guard nor #pragma once will help because their purpose is to avoid violating the one definition rule for entities that must not be defined more than once within a translation unit (source file + included headers). As -Adrian pointed out in post #5, the issue is that an object was defined in a header at namespace scope, so its name has external linkage. This means that when the header is included in multiple translation units, the name refers to the same object in each of the transaltion units, hence the object is defined multiple times across the program. This violates the one definition rule for such objects: these must be defined once across the entire program, not merely once per translation unit.

    Speaking of the one definition rule, I was mistaken about the typedef: it is explicitly listed as a declaration that is not a definition, so it does not fall under the one definition rule, i.e., as long as you don't have conflicting declarations, you can declare the typedef multiple times in the same scope within a translation unit without violating the one definition rule, hence the use of inclusion guards would not strictly be necessary for a header consisting entirely of typedef declarations.
    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
    May 2008
    Posts
    106
    To follow up on templates. Putting this function in the header (along with
    Code:
    #include <iostream>
    and
    Code:
    #include <vector>
    )

    Code:
    template <typename T>
    void PrintVector(const std::vector<T>& vector)
    {
    	for (const auto& element : vector) std::cout << " " << vector;
    }
    also does not compile. But why?

    As for the guards, I putting both the regular guards and pragma each header file. I believe there is no harm in putting both in.

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    27,183
    You probably want to print element instead of vector.

    Btw, instead of just saying "it does not compile", post the compile error.
    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

  12. #12
    Registered User
    Join Date
    May 2008
    Posts
    106
    Yes, I made a cut-and-paste error - vector should be element. The problem that I have is this:

    1. Header (utilities.h)

    Code:
    #ifndef UTILITIES_H
    #define UTILITIES_H
    #pragma once
    
    #include <iostream>
    #include <vector>
    
    template <typename T>
    void PrintVector(const std::vector<T>& vector);
    
    #endif
    2. Implementation (utilities.cpp)

    Code:
    #include "utilities.h"
    
    template <typename T>
    void PrintVector(const std::vector<T>& vector)
    {
    for (const auto& element : vector) std::cout << ";" << element;
    }
    3. Main

    Code:
    #include "utilities.h"
    4. Linker-error (in Microsoft VS):

    Code:
    Severity Code Description Project File Line Suppression State Suppression State
    Error LNK2019 unresolved external symbol "void __cdecl PrintVector<int>(class std::vector<int,class std::allocator<int> > const &)" (??$PrintVector@H@@YAXABV?$vector@HV?$allocator@H@std@@@std@@@Z) referenced in function _main mysim D:\devvs\mysim\main.obj 1

  13. #13
    Informer -Adrian's Avatar
    Join Date
    Jan 2013
    Posts
    814
    Have you added utilities.cpp to your project as a dependency, so that it gets linked? (I don't know how VS works)

  14. #14
    Informer -Adrian's Avatar
    Join Date
    Jan 2013
    Posts
    814
    Oh, you're using templates! Sorry, totally missed that. As laserlight said, move the implementation into the header.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Header Files Typedef Redefintion
    By seal308 in forum C Programming
    Replies: 10
    Last Post: 04-05-2016, 04:39 PM
  2. How do we typedef a forwards declaration ?
    By see the big C in forum C Programming
    Replies: 1
    Last Post: 12-05-2010, 03:43 PM
  3. Bisection with typedef declaration
    By idecline in forum C Programming
    Replies: 13
    Last Post: 11-21-2010, 11:57 AM
  4. Typedef in a header?
    By dnguyen1022 in forum C++ Programming
    Replies: 1
    Last Post: 04-19-2009, 09:51 PM
  5. include library header in header files
    By Raison in forum C++ Programming
    Replies: 6
    Last Post: 09-27-2004, 02:50 AM

Tags for this Thread