CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 15 of 15
  1. #1
    Join Date
    May 2009
    Location
    Boston
    Posts
    364

    global constants and custom operators

    Hello,

    I am working on a computational geometry program where I need to make comparisons to numbers like pi. In addition to the normal floating point issues, pi has not absolute value so when evaluation if some number is equal to pi, you are asking if the value is within some tolerance of pi to some specific number of decimal places. The == operator doesn't quite cut it here.

    I have to do this from many different src files, so I created a header file with the values for the constants I am using. I also decided to place the definitions for the custom operators in the same header file instead of in a separate src file. I also placed all of the above in a namespace.

    For example,

    Code:
    // in file "constants.h"
    
    // constants and custom comparison operators
    namespace constants {
    
       // value of pi, radian equivalent of 180 degrees (pi to 19 decimal places)
       const double pi_value = 3.1415926535897932384;
    
       // tolerance
       const double epsilon = 0.000000001;
    
       // custom operator to check if a passed double is equal to pi radians (180 degrees)
       // equal is defined as falling in the range of pi +/- epsilon inclusive or
       // 3.141592652 to 3.141592654
       inline bool eq_pi_pme(const double &check) {
    
          // return bool, false by default
          bool return_value = false;
    
          // true if check_value falls between pi + epsilon and pi - epsilon inclusive
          if( check >= (constants::pi_value - constants::epsilon) &&
              check <= (constants::pi_value + constants::epsilon) ) {
             return_value = true;
          }
    
       return return_value;
       }
    
    }
    this is used as,

    Code:
    // include header
    #include "constants.h"
    
    // value of some angle
    double angle_value == 1.1;
    
    // evaluate against constant using custom operator
    if( constants::eq_pi_pme(angle_value) ) { cout << "angle is equal to pi within tolerance" << endl; }
    I just include the header file in the src files where I need the operators. The custom operator functions are declared as inline and my understanding is that is what prevents "multiple definition" errors from the linker.

    This compiles and runs, but I know it is not generally considered optimal to include function definitions in header files and I would like to know if there are problems with what I have implemented here and it there is a more correct method.

    Thanks,

    LMHmedchem
    Last edited by LMHmedchem; July 17th, 2018 at 11:41 AM.

  2. #2
    VictorN's Avatar
    VictorN is offline Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Hanover Germany
    Posts
    20,396

    Re: global constants and custom operators

    Quote Originally Posted by LMHmedchem View Post
    This compiles and runs, but I know it is not generally considered optimal to include function definitions in header files
    Why do you think so?
    It seems indeed pretty reasonable.
    Victor Nijegorodov

  3. #3
    Join Date
    May 2009
    Location
    Boston
    Posts
    364

    Re: global constants and custom operators

    Quote Originally Posted by VictorN View Post
    Why do you think so?
    It seems indeed pretty reasonable.
    When I was learning c++, everything I read said that header files were for function declarations and not function definitions. Also, there always seemed to be a "multiple declaration" linker error when I tried it.

    In other cases, when I declared a global variable, I would declare it in a header file as extern and then also declare it in one src file, but not as extern. Then I could include the header in any other file where the global may be needed. In this case, the constants like pi are only declared in the header file, they are not declared as extern, and they are not declared in any src file. I guess I am wondering why this works as implemented. Does it work because the constants are declared in a namespace? Does it works because the variables are declared as constants? Why don't the variables need to be declared as extern and also be declared in one src file where the header is included?

    My understanding of why I don't get a "multiple declaration" linker error for the operator functions is that they are declared as "inline". Is that correct?

    As always, I am also looking to see if the is a more c++'ish way of doing this. Just because it works doesn't mean it's the best solution.

    Thanks for the input,

    LMHmedchem
    Last edited by LMHmedchem; July 17th, 2018 at 03:35 PM.

  4. #4
    Join Date
    Feb 2017
    Posts
    677

    Re: global constants and custom operators

    Quote Originally Posted by LMHmedchem View Post
    As always, I am also looking to see if the is a more c++'ish way of doing this. Just because it works doesn't mean it's the best solution.
    C++ doesn't require you to put declarations in header files (.h) and definitions in source files (.cpp). It's just an old convention. I put everything on .h files and only the program entry point on a .cpp file. In C++ terminology this means the whole program is one single compilation unit. That may be too extreme for you but my point is that it's possible and works fine (I'm using VS 2017 Community). Actually it's something of a trend today for third-party library suppliers to put whole libraries on .h files, compare for example Boost.

    When you use .h files for both declarations and definitions there are two things to remember. Firstly, free functions (that aren't templates) must be declared inline (as you've already noted). Secondly, every .h file must have a unique include guard. This is how a typical compiler independent include guard would look like,

    Code:
    // in file "constants.h"
    
        // start of include guard (put at the very beginning of the include file)
        // (the SOME_UNIQUE_SYMBOL symbol must be exclusive to this include file
        // and may not appear anywhere else in the entire source code of the program)
    #ifndef SOME_UNIQUE_SYMBOL
    #define SOME_UNIQUE_SYMBOL
    
        // here other headers may be included like say
    #include <string>
    #include "someotherincludefile.h"
    
        // here you put the specific declarations/definitions of this include file
        // like constants, classes, free functions and whatever other language elements you wish to use
        // preferably inside a namespace (which can be shared among several include files)
    namespace constants {
        // ...
    }
    
        // end of include guard (put at the very end of the include file)
    #endif
    Just a few comments to your code:

    1. Note that the pi_value constant isn't correctly rounded. The digit following the last digit 4 is 6 so the last digit should be 5. Since the precision of pi_value exceeds the precision of a double it may not matter but still.

    2. You don't have to qualify symbols declared inside a namespace with the namespace. So inside constants you don't need to do constants::pi_value, it's enough to do pi_value.

    3. I think most C++ programmers would pass the check parameter by value rather than const reference since double is a primitive type and thus cheap to copy.

    4. I'd say it's idiomatic C++ to write the eq_pi_pme function like this but it's all a matter of taste of course,
    Code:
       inline bool eq_pi_pme(const double check) {
           return check >= (pi_value - epsilon) && check <= (pi_value + epsilon);
       }
    Last edited by wolle; July 18th, 2018 at 03:00 AM.

  5. #5
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: global constants and custom operators

    PI is actually defined for c++ in cmath (don't forget the #define). See https://docs.microsoft.com/en-us/cpp...math-constants

    For the check, I've always used

    Code:
    inline bool eq_pi_pme(const double check) {
        return fabs(check - pi_value) < epsilon;
    }
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  6. #6
    Join Date
    May 2009
    Location
    Boston
    Posts
    364

    Re: global constants and custom operators

    Quote Originally Posted by wolle View Post
    When you use .h files for both declarations and definitions there are two things to remember. Firstly, free functions (that aren't templates) must be declared inline (as you've already noted). Secondly, every .h file must have a unique include guard.
    I have only used compiler directives to compile/not compile a block of code based on the operating system or some feature that may be turned on or off. My current code does not have an include guard for the constants.h file, or for any header file. The code compiles and executes without it so what is it that the include guard does? What are the situations where I will get into trouble without it. It is easy enough to add to every header file if that is best practice but it would be helpful to understand what is going on under the hood.

    Quote Originally Posted by wolle View Post
    1. Note that the pi_value constant isn't correctly rounded. The digit following the last digit 4 is 6 so the last digit should be 5. Since the precision of pi_value exceeds the precision of a double it may not matter but still.
    Yes, I didn't actually round pi as I remember. I just entered it to 20 digits (somehow I ended up with 19). I wasn't sure what epsilon I would be using but I was sure it would be larger than 10^-20 since machine epsilon is probably 10^-14 or 15. I didn't think that rounding would change anything. Is it the convention to always round the last digit if additional precision is known?

    Quote Originally Posted by wolle View Post
    2. You don't have to qualify symbols declared inside a namespace with the namespace. So inside constants you don't need to do constants::pi_value, it's enough to do pi_value.
    Thanks, in my first version the functions were in the header file but not in the namespace. I never changed it back after I moved the functions.

    Quote Originally Posted by wolle View Post
    3. I think most C++ programmers would pass the check parameter by value rather than const reference since double is a primitive type and thus cheap to copy.
    I have always passed by reference if the function doesn't need its own copy of the data for some reason, meaning that the function will make changes to the copy and not to the original. Also, I have always thought that it wasted resources to make a copy of a variable instead of using the address of an existing variable.

    I am sure the resource usage is a trivial issue at this point. It wasn't back in the f77 days. What exactly is the functional difference between a primitive passed by value and by reference? It is just that the primitive is so lightweight that it isn't worth worrying about or does the compiler actually make a copy anyway when you pass a primitive by reference?

    Quote Originally Posted by wolle View Post
    4. I'd say it's idiomatic C++ to write the eq_pi_pme function like this but it's all a matter of taste of course,
    Code:
    inline bool eq_pi_pme(const double check) {
           return check >= (pi_value - epsilon) && check <= (pi_value + epsilon);
       }
    That's interesting, I really don't know the shorthand of c++ very well. To me, this reads that the function will return something undefined when the conditions are met but never return if the conditions are not met. Obviously that's not true but that's what it looks like when I read it.

    I tend to write more like this,
    Code:
    // check if a passed double is equal to 2pi (360 degrees)
    // equal is defined as falling in the range of 2pi +/- epsilon inclusive
    // 6.283185306 to 6.283185308
    inline bool eq_pi_times_2_pme(const double &check) {
    
       // return bool
       bool return_value;
    
       // true if check_value falls between pi + epsilon and pi - epsilon inclusive
       if( check >= (pi_times_2 - epsilon) && check <= (pi_times_2 + epsilon) ) { return_value = true; }
    
       // false if check_value falls outside pi + epsilon and pi - epsilon, not inclusive
       else { return_value = false; }
    
     return return_value;
     }
    What is happening in the function is more clear to me with this version and a year from now I may actually remember what the function is doing. What I originally posted is a bit more condensed. What would be the difference in the assembler written by the compiler for these two versions of the function?

    Quote Originally Posted by 2kaud View Post
    PI is actually defined for c++ in cmath (don't forget the #define). See https://docs.microsoft.com/en-us/cpp...math-constants
    I don't remember why I didn't use a predefined constant. I seem to remember looking for it and not finding it. I was also thinking I would define it to some specific number of decimal places and so hard coded it. So it looks like I just need to do something like,

    Code:
    #include <math.h>
    #define _USE_MATH_DEFINES
    // pi == M_PI
    Is that correct? Do I need to do that in every src file where I evaluate pi? Would it work to just add the above to the constants.h file that I am already including?

    Quote Originally Posted by 2kaud View Post
    For the check, I've always used
    Code:
    inline bool eq_pi_pme(const double check) {
        return fabs(check - pi_value) < epsilon;
    }
    For this sort of thing I am generally looking for the solution that gives me reproducibility to the most decimal places. Will using the above version make any difference with that? Sorry if I am not being clear.

    LMHmedchem

  7. #7
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: global constants and custom operators

    Is that correct? Do I need to do that in every src file where I evaluate pi? Would it work to just add the above to the constants.h file that I am already including?
    The #define has to come before the #include. You can add the #define and #include to the constants.h file without any problems. Note that cmath has a lot more defined constants. Have a look.

    For this sort of thing I am generally looking for the solution that gives me reproducibility to the most decimal places. Will using the above version make any difference with that? Sorry if I am not being clear.
    fabs() returns a type the same as that provided - so if given a double, returns double, given long double returns long double etc. If passed an integral type (ie int) it returns double.

    so what is it that the include guard does?
    It prevents the same code from being included more than once in the same compilation unit. If you #include constants.h and then #include a different file that it itself has #include constants.h then you could get compiler errors about duplicate definitons. That is why you use code guards. If your compiler supports it, there is also #pragma once which you put as the first line in all #include files. See https://msdn.microsoft.com/en-us/library/4141z1cx.aspx

    Also, I have always thought that it wasted resources to make a copy of a variable instead of using the address of an existing variable.
    Pass by reference is in effect pass a pointer by value - so there is still a copy being done but it's only a single 32 or 64 bit copy of the pointer. The actual overhead of passing a double by value as opposed to by ref is nill! Only if you are passing a data item that is greater in size then 64 bits do you consider passing by ref (and always if dynamic memory is involved unless a copy is needed).

    Code:
    // check if a passed double is equal to 2pi (360 degrees)
    // equal is defined as falling in the range of 2pi +/- epsilon inclusive
    // 6.283185306 to 6.283185308
    inline bool eq_pi_times_2_pme(const double &check) {
    
       // return bool
       bool return_value;
    
       // true if check_value falls between pi + epsilon and pi - epsilon inclusive
       if( check >= (pi_times_2 - epsilon) && check <= (pi_times_2 + epsilon) ) { return_value = true; }
    
       // false if check_value falls outside pi + epsilon and pi - epsilon, not inclusive
       else { return_value = false; }
    
     return return_value;
     }
    That's the old structured code way of coding - one way in and one way out! Keeping 'your way' this could be written as

    Code:
    // check if a passed double is equal to 2pi (360 degrees)
    // equal is defined as falling in the range of 2pi +/- epsilon inclusive
    // 6.283185306 to 6.283185308
    inline bool eq_pi_times_2_pme(const double &check) {
    
       // true if check_value falls between pi + epsilon and pi - epsilon inclusive
       if ( check >= (pi_times_2 - epsilon) && check <= (pi_times_2 + epsilon) ) 
          return true;
    
       // false if check_value falls outside pi + epsilon and pi - epsilon, not inclusive
       return false;
     }
    The 'trick' in Wolle's code - and it's widely used - is that a condition test returns either true or false. So

    Code:
    check >= (pi_value - epsilon) && check <= (pi_value + epsilon);
    returns either true or false - which is exactly what you want the function to return. So there's no need to check the return value and explicitly return true or false - just return the result of the condition test. Note that if you rewrite this function not to use a local variable, then the function can be declared as constexpr.
    Last edited by 2kaud; July 18th, 2018 at 01:25 PM.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  8. #8
    Join Date
    May 2009
    Location
    Boston
    Posts
    364

    Re: global constants and custom operators

    This is my most recent version of the constants header file,
    Code:
    // constants_geo.h header file define constants_geo namespace
    
    #define _USE_MATH_DEFINES  // to define pi
    #include <math.h>          // for math defines
    
    // include guard
    #ifndef CONSTANTS_GEOMETRY
    #define CONSTANTS_GEOMETRY
    
    // constants used for custom comparison operators
    namespace constants_geo {
    
       // value of 2pi, radian equivalent of 360 degrees (pi*2 to 21 decimal places)
       // 6.283185307179586231996
       const double pi_times_2 = M_PI * 2;
    
       // value of pi, radian equivalent of 180 degrees (pi to 21 decimal places)
       // 3.14159265358979323846
       const double pi_value = M_PI;
    
       // value of pi/2, radian equivalent of 90 degrees (pi/2 to 21 decimal places)
       // 1.570796326794896557999
       const double pi_over_2 = M_PI / 2;
    
       // tolerance
       const double epsilon = 0.000000001;
    
       // custom operators for 360 degree checks ---------------------------------------------//
    
       // check if a passed double is equal to 2pi (360 degrees)
       // equal is defined as falling in the range of 2pi +/- epsilon inclusive
       // 6.283185306 to 6.283185308
       inline bool eq_pi_times_2_pme(const double check) { return fabs(check - pi_times_2) < epsilon; }
    
       // check if a passed double is greater than 2pi (360 degrees)
       // greater than is defined as larger 2pi + epsilon
       // > 6.283185308
       inline bool gt_pi_times_2_pe(const double check) { return check > (pi_times_2 + epsilon); }
    
       // check if a passed double is less than 2pi (360 degrees)
       // less than is defined as smaller than 2pi + epsilon
       // < 6.283185306
       inline bool lt_pi_times_2_me(const double check) { return check < (pi_times_2 - epsilon); }
    
       // custom operators for 180 degree checks ---------------------------------------------//
    
       // check if a passed double is equal to pi (180 degrees)
       // equal is defined as falling in the range of pi +/- epsilon inclusive
       // 3.141592652 to 3.141592654
       inline bool eq_pi_pme(const double check) { return fabs(check - pi_value) < epsilon; }
    
       // check if a passed double is greater than pi (180 degrees)
       // greater than is defined as larger than pi + epsilon
       // > 3.141592654
       inline bool gt_pi_pe(const double check) { return check > (pi_value + epsilon); }
    
       // check if a passed double is less than pi (180 degrees)
       // less than is defined as less than pi - epsilon
       // < 3.141592652
       inline bool lt_pi_me(const double check) { return check < (pi_value - epsilon); }
    
       // custom operators for 90 degree checks ----------------------------------------------//
    
       // check if a passed double is equal to pi/2 (90 degrees)
       // equal is defined as falling in the range of pi/2 +/- epsilon inclusive
       // 1.570796325 to 1.570796327
       inline bool eq_pi_over_2_pme(const double check) { return fabs(check - pi_over_2) < epsilon; }
    
       // check if a passed double is greater than pi/2 (90 degrees)
       // greater than is defined as greater than pi/2 + epsilon
       // > 1.570796327
       inline bool gt_pi_over_2_pe(const double check) { return check > (pi_over_2 + epsilon); }
    
       // check if a passed double is less than pi/2 (90 degrees)
       // less than is defined as less than pi/2 - epsilon
       // < 1.570796325
       inline bool lt_pi_over_2_me(const double check) { return check < (pi_over_2 - epsilon); }
    
       // custom operators for 0 degree checks -----------------------------------------------//
    
       // check if a passed double is equal to 0
       // equal is defined as falling in the range of 0 +/- epsilon inclusive
       // this just checks if the absolute value of check is smaller than epsilon
       // -0.000000001 to 0.000000001
       inline bool eq_0_pme(const double check) { return fabs(check) < epsilon; }
    
       // check if a passed double is greater than 0
       // greater than is defined as greater than 0 + epsilon
       // > 0.000000001
       inline bool gt_0_pe(const double check) { return check > epsilon; }
    
       // check if a passed double is less than 0
       // less than is defined as less than 0 + (-epsilon)
       // have to check against -epsilon
       // < -0.000000001
       inline bool lt_0_me(const double check) { return check < -epsilon; }
    
    } // end of constants namespace
    
    #endif
    I remember that one reason I didn't use the predefined constants in math.h was that I wasn't sure I could define a constant as the result of an expression like,
    Code:
    const double pi_times_2 = M_PI * 2;
    Since I not only needed pi, but also pi/2, 2*pi, etc, I just printed the result of those expressions to 22 places and then hard coded the output. Since the above works, I guess I didn't need to worry about the constants.

    The above is still more verbose than necessary in that I guess I could just do,
    Code:
    inline bool eq_pi_times_2_pme(const double check) { return fabs(check - (M_PI * 2) ) < epsilon; }
    Instead of defining a value for pi*2.

    Is there anything else that could be improved with this implementation?

    LMHmedchem

  9. #9
    Join Date
    Feb 2017
    Posts
    677

    Re: global constants and custom operators

    Quote Originally Posted by LMHmedchem View Post
    My current code does not have an include guard for the constants.h file, or for any header file. The code compiles and executes without it so what is it that the include guard does?
    It's essential that every include file has a guard. If not, sooner or later the same include file will be included twice (or more) in your source code. This will give rise to spurious compiler error messages and it can be very hard to figure out what's wrong and what to do about it. In the C++ Core Guidelines by Stroustrup & Sutter it's rule SF.8:

    https://github.com/isocpp/CppCoreGui...eGuidelines.md

    Is it the convention to always round the last digit if additional precision is known?
    Well, at least mathematically it's the right thing to do. It may or may not matter depending on how the constant is used but it does matter if the full precision of the constant is utilized so better safe than sorry.

    Also, I have always thought that it wasted resources to make a copy of a variable instead of using the address of an existing variable.
    It may be, but not always. If you pass by value the variable gets copied and if you pass by const reference the address to the variable gets copied. In the case of a primitive (like an int or a double) the cost of these two passing mechanisms will be roughly the same. The difference comes next when the variable has been passed and is used in the function. Then it's cheaper to access it directly than indirectly via its address. For this reason most C++ programmers will pass primitives by value. In the C++ Core Guidelines I mentioned above it's rule F.16 (in the first example compare functions f3 and f4).

    What is happening in the function is more clear to me with this version and a year from now I may actually remember what the function is doing. What I originally posted is a bit more condensed. What would be the difference in the assembler written by the compiler for these two versions of the function?
    It's perfectly fine the way you do it. I just mentioned the idiomatic C++ way so you know that style if you see it (and maybe you will warm up to it eventually ). An optimizing compiler probably will produce the same code anyway. An intermediate version would be,

    Code:
    inline bool eq_pi_times_2_pme(const double check) {
            // the right hand side of the assignment evaluates to a bool
        bool return_value = (check >= (pi_times_2 - epsilon) && check <= (pi_times_2 + epsilon));    
        return return_value;
     }
    Here it is clear that the introduction of the bool variable really isn't necessary and you arrive at the idiomatic version.
    Last edited by wolle; July 19th, 2018 at 02:55 AM.

  10. #10
    Join Date
    Feb 2017
    Posts
    677

    Re: global constants and custom operators

    Quote Originally Posted by LMHmedchem View Post
    Is there anything else that could be improved with this implementation?
    Note that the include guard should always be at the very top of the file it is guarding.

    Comparing these options,
    Code:
    return check >= (pi - epsilon) && check <= (pi + epsilon); // 1 - what you had first
    
    return fabs(check - pi) < epsilon; // 2 - what you have now
    For these two options to be equivalent I think the < in the second option should be <=. It's because if epsilon is zero and check is identical to pi then the result will be false and not true as it should. It's a corner case but still.

    Apart from that I prefer the second option (suggested by 2kaud) as you also did. The intent is clearer and it's probably faster since the implementation of fabs most likely is branch-free whereas the first option has an implicit branch due to && (so somewhat ironically, replacing && with & here actually could result in faster code on today's processors).
    Last edited by wolle; July 19th, 2018 at 05:05 AM.

  11. #11
    Join Date
    May 2009
    Location
    Boston
    Posts
    364

    Re: global constants and custom operators

    I have been going through the header files for this project and adding include guards. This is a simple header that declares a function called by main().
    Code:
    // process_funcs.h
    // data processing functions called by main()
    
    // process point_B and populate result object
    extern void process_point(result_object &current_result, row_data& point_B, vector<row_data>& rows_data);
    The function is defined in process_funcs.cpp which includes process_funcs.h. I have added an include guard,
    Code:
    // process_funcs.h
    // data processing functions called by main()
    
    // include guard
    #ifndef PROCESSING_FUNCTIONS
    #define PROCESSING_FUNCTIONS
    
    // process point_B and populate result object
    extern void process_point(result_object &current_result, row_data& point_B, vector<row_data>& rows_data);
    
    // end include guard
    #endif
    If I understand rule "SF.11: Header files should be self-contained" then the header should actually look like,
    Code:
    // process_funcs.h
    // data processing functions called by main()
    // requires rows_data.h for the definition of the row_data class
    // requires vector_data.h for the definition of the result_object class
    
    // include guard
    #ifndef PROCESSING_FUNCTIONS
    #define PROCESSING_FUNCTIONS
    
    #include <vector>
    #include "rows_data.h"   // for row_data object
    #include "vector_data.h" // for result_object object
    
    // process point_B and populate result object
    extern void process_point(result_object &current_result, row_data& point_B, vector<row_data>& rows_data);
    
    // end include guard
    #endif
    Am I understanding this philosophy correctly?

    I have generally handled this by putting the includes in the right order in the src files where they are included such that, in this case, main.cpp and process_funcs.cpp would have,
    Code:
    #include <vector>
    #include "rows_data.h"
    #include "vector_data.h"
    #include "process_funcs.h"  // requires <vector>, rows_data.h, and vector_data.h
    where the includes are in the necessary order and the order is documented.

    I do sometimes include the std library includes like <vector> and <string> in header files that may be included in many files that may or may not already have all the dependent includes. It seems like including everything everywhere would result in messy code. Does the pre-processor just recognize that something like <vector> has already been included in main so it is not necessary to insert it along with the rest of the header file? Does the pre-processor just skip included code that is already there where it needs to be?

    LMHmedchem
    Last edited by LMHmedchem; July 19th, 2018 at 12:08 PM.

  12. #12
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: global constants and custom operators

    If I understand rule "SF.11: Header files should be self-contained" then the header should actually look like,
    Yes. But using... shouldn't be in a header file (or before they are included). So

    Code:
    extern void process_point(result_object &current_result, row_data& point_B, vector<row_data>& rows_data);
    shouldn't compile. It should be

    Code:
    extern void process_point(result_object &current_result, row_data& point_B, std::vector<row_data>& rows_data);
    Does the pre-processor just recognize that something like <vector> has already been included in main so it is not necessary to insert it along with the rest of the header file?
    Yes - by the use of include guards!

    Don't assume that an include includes things that the program needs (with the exception of pre-compiled headers). If a header file includes say <vector> and the main program also uses vector, then the main program should also include <vector>.

    PS

    Code:
    inline bool gt_pi_pe(const double check) { return check > (pi_value + epsilon); }
    epsilon would usually be by itself on one side of a condition. So
    Code:
    inline bool gt_pi_pe(const double check) { return epsilon < (check - pi_value); }
    Last edited by 2kaud; July 19th, 2018 at 12:40 PM.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  13. #13
    Join Date
    May 2009
    Location
    Boston
    Posts
    364

    Re: global constants and custom operators

    Quote Originally Posted by 2kaud View Post
    using... shouldn't be in a header file (or before they are included).
    I have always inserted the namespace declaration before the includes so I wouldn't have to expand everything in the header files. It's no problem to change but why is it a problem to declare the namespace before the includes.

    Quote Originally Posted by 2kaud View Post
    Don't assume that an include includes things that the program needs (with the exception of pre-compiled headers). If a header file includes say <vector> and the main program also uses vector, then the main program should also include <vector>.
    I have reworked everything based on the principle that every header file should compile on its own without depending on includes that are in a src file where the header has been inserted. That seems reasonable and a rule that is easy enough to understand in a given situation.

    Quote Originally Posted by 2kaud View Post
    epsilon would usually be by itself on one side of a condition. So
    Code:
    inline bool gt_pi_pe(const double check) { return epsilon < (check - pi_value); }
    That is interesting. It it just convention or is there some other reason?

    So my custom equals operator would be,
    Code:
    inline bool eq_pi_times_2_pme(const double check) { return  epsilon >= fabs(check - pi_times_2); }
    instead of,
    Code:
    inline bool eq_pi_times_2_pme(const double check) { return fabs(check - pi_times_2) <= epsilon; }
    That will require some care to make the changes and make sure I get all of the greater and less than signs correct.

    I have made all of the suggested changes and spent a while running down compiler errors. I think that most everything is working again now and hopefully the code is better formed.

    LMHmedchem

  14. #14
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: global constants and custom operators

    re your custom equals operator. You already have epsilon by itself on one side of the condition??
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  15. #15
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: global constants and custom operators

    Quote Originally Posted by LMHmedchem
    I have always inserted the namespace declaration before the includes so I wouldn't have to expand everything in the header files. It's no problem to change but why is it a problem to declare the namespace before the includes.[/
    This is bad for two reasons:
    • Your header files are no longer self-contained, i.e., it is now an unusual mysterious convention that when someone includes your header files, they must first have a using directive/declaration before the header inclusion.
    • Like it or not, those who include your headers have to accept the names from your namespace being injected into the global namespace. This goes against the benefit of namespaces, i.e., now they have to be careful not to use names that you used. If you did not have using directives/declarations at namespace scope in your header file, and if you did not require that there be a using directive/declaration before including your header file, then those who include your header files would fully benefit from the use of namespaces, e.g., they could decide whether or not they want to inject names from your namespace into the global namespace.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured