juli (caladri) wrote in dailysrc,
juli
caladri
dailysrc

Using method-static data for static data in templated classes.

For a long time, I've been looking for ways to include static members of templated classes that don't require consumers to instantiate the templated classes' static members in their own code. My results have failed to materialize. Many shortcuts that are decidedly less ugly are mentioned on the Internet, but fail to work outside of specific Microsoft compilers or specific GNU compilers. Moreover, the GNU line is moving towards a more strict language that is closer to the standard, so some once-acceptable shortcuts in the GNU language are no longer workable. Frustratingly, static members prove impossible to instantiate without providing an initializer, which is problematic for void-constructored static members, as the compiler seems to want to treat them as either a forward-declaration of the variable, rather than a definition, or (if you parenthesise) as a forward-declaration of a method.

A solution (though I have not verified if this is standard) is to make the data static to a static member function. This also (perhaps unwantedly, if one is wanting to use static members to e.g. perform startup tasks) introduces lazy allocation to the fold, only constructing the static member when its use is requested. This is also how we can end up with a simple template for Singleton classes, as:

template<typename T>
class Singleton {
public: static T *instance(void) { static T object; return (&object); }
};


Note that it is, in this case, also possible to return a reference to the object and still maintain lazy-allocation (if your compiler delays allocation and initialization of static data in static methods until their first invocation), unlike with the traditional static-pointer method, though this may complicate locking, though many compilers seem to synchronize the process of creation of static data, as here, but I am not sure if they guarantee against two invocations of the method using two different cases of data, or if they merely guard against use of incomplete values for the static data.

Extensive tests have shown that (at least with my compiler) each templated version of the class will get unique static data for its static methods. In the singleton case, this is obviously required, and it is probably semantically required even in other cases, as each static method is distinct.

Note also that the problems with the compiler's misparse of void-constructored static data definitions does not occur with this, as (without extern) this will always be treated as a definition when in non-global scope.


#include <iostream>

template<typename T>
class Bit {
        unsigned bit_;
public:
        Bit(void)
        : bit_(bit_alloc())
        {
        }

        ~Bit()
        {
        }

        uintmax_t mask(void) const
        {
                return ((uintmax_t)1 << bit_);
        }

private:
        static unsigned bit_alloc(void)
        {
                static unsigned bit;
                return (bit++);
        }
};

enum One {};
enum Two {};

int
main(void)
{
        Bit<One> one, two;
        Bit<Two> three;

        std::cout << one.mask() << std::endl;
        std::cout << two.mask() << std::endl;
        std::cout << three.mask() << std::endl;
        return (0);
}

  • Post a new comment

    Error

    default userpic

    Your IP address will be recorded 

  • 0 comments