0

I'm making class, that should help with minor deficiencies of C++, like comparing double with other double with defined precision, and so on.

I have namespace Utilities, where class Double exists:

namespace Utilities {

void init();

class Double {
public:
    //! @brief Compares the equality of two doubles with defined precision
    static bool fuzzyCompare(const double &d1,const double &d2);

    static void setFuzzyComparePrecision(int precision);
private:
    //! @brief Private constructor
    Double() {};

    static int fuzzyComparePrecision_;
};

}

I want this class to contain only static members and not be instantiable. Current idea is to call Utilities::init() function in void main(), which initializes default values for members of class Double.

Is it possible to set default fuzzyComparePrecision_ without calling function init() in void main()? Or in other words, is it possible to set default value of fuzzyComparePrecision_ without instance of Double and without calling other function such as init()?

Thanks for your help!

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Brykyz
  • 587
  • 4
  • 30
  • 1
    BTW. Why do you create a class for that? Free functions would be nicer here (unless you need to unit test this, but you can't substitute singleton like this anyway). – Yksisarvinen Jul 25 '19 at 10:32
  • @Yksisarvinen But, how can I initialize static members? When I do it in class definition, there is error during compilation, because my static members are not constant and I can't set value for them in .cpp file, because those members are private. – Brykyz Jul 25 '19 at 10:36
  • 1
    Another BTW, `main()` returns `int` in standard C++, not `void`. It is possible to initialise static class members by defining them with an initialiser outside the class definition (in exactly one compilation unit) – Peter Jul 25 '19 at 10:36
  • @Peter I know, but within this context, it doesn't matter – Brykyz Jul 25 '19 at 10:37
  • 2
    @Brykyz It does matter. `void main()` is ill-formed. – L. F. Jul 25 '19 at 10:39
  • 1
    Possible duplicate of [How to initialize private static members in C++?](https://stackoverflow.com/questions/185844/how-to-initialize-private-static-members-in-c) –  Jul 25 '19 at 10:47
  • @Yksisarvinen BTW, I use classes because I want to keep some variables in private context. If I use free functions, I would need to use global variables, and I don't want it. – Brykyz Jul 25 '19 at 10:51
  • 2
    Why don't you make Double a namespace and implement all of those as functions? After all, that is what they are. Doing it with a class looks pretty much like Java style - are you coming from there? Other than that, the init function looks like code smell. The code should work even when somebody forgot about this. If you want to use constants, better have variables with the `constexpr` keyword, or, in your contex, use something like `std::numeric_limits::epsilon()`. – Aziuth Jul 25 '19 at 10:52
  • In addition, if you want to use private variables like you wrote a moment ago, consider declaring them in the corresponding source file. Depends on the context. If we talk about a double precision threshold, and you really want to hide it for some reason, go with a `constexpr` in the source file. – Aziuth Jul 25 '19 at 10:54

2 Answers2

2

It's not only possible, it's (almost) required to do so.

Starting from C++17, you can declare any static variable as inline, and initialize it in class body:

class Double {
private:
    inline static int fuzzyComparePrecision_ = 0;
};

Before C++17, every* static class member requires an out-of-class definition.

It can (and usually should) be combined with initialization, to avoid dealing with uninitialized variables.

You have to provide the following (in cpp file):

int Utilities::Double::fuzzyComparePrecision_;

But you can also extend it with initialization:

int Utilities::Double::fuzzyComparePrecision_ = 0;

*There are exceptions - const static members can be initialized in class body with another constant expression.

Yksisarvinen
  • 18,008
  • 2
  • 24
  • 52
2

To initialize static member variables you have two ways:

  1. If you are using C++17 you can do this with inline static member variables:
    class Double {
    private:
        inline static int fuzzyComparePrecision_ = 2;
    }
    
  2. For earlier version of C++ you have to do it outside the class declaration in a source file (it can't be in a header file):
    class Double {
    private:
        static int fuzzyComparePrecision_;
    }
    
    int Double::fuzzyComparePrecision_ = 2;
    
  • _"To make your class not instanciable, declare it as static"_ Can you link us to a live demo of this working? – Lightness Races in Orbit Jul 25 '19 at 10:43
  • Just curious, is there any big difference between those ways? In other words, are there any cases which requires first or second solution? – Brykyz Jul 25 '19 at 10:49
  • 1
    @Brykyz There are two differences: The first method is only available in modern C++17 compilers; The first method can be used in header files and eases the creation of header-only libraries. –  Jul 25 '19 at 10:52
  • Other than that no. I still quite like out-of-class definitions, personally, but in practice it's hard to think of an objective reason to use them nowadays, at least in the sense that they have no notable advantages over the `inline` variety that I can think of – Lightness Races in Orbit Jul 25 '19 at 10:59
  • @LightnessRacesinOrbit Thanks for pointing out that static classes can be instantiated. I never tried that before and somehow assumed that obviously this must be the usage of the keyword. Was just always a bit wondering about why do members still have to be marked as static explicitly... ;) –  Jul 25 '19 at 11:05
  • @YanB. It's more that static classes _don't exist_. `static class` is [not a thing](https://coliru.stacked-crooked.com/a/96e553eba30c14b1) that you can write in a well-formed C++ program*. Please don't write random guesses/assumptions into answers! – Lightness Races in Orbit Jul 25 '19 at 11:34
  • * Except for unrelated cases like `static class T {} obj;` :D (there it's the instance `obj` that's static) – Lightness Races in Orbit Jul 25 '19 at 11:35