#include <iostream>
#include <string>
#include <stdexcept>

//Some made up configuration data for a Foo class.
struct FooConfig
{
    int i;
    double d;
};

//Some made up configuration data for a Bar class.
struct BarConfig
{
    int x;
    double y;
};

//Configurations can be shared among classes.
struct SharedConfig
{
    std::string text;
};

//The actual wrapper.
template <class T>
class StaticConfig
{
public:

    StaticConfig()
    {
        if (!mIsInitialised)
        {
            throw std::runtime_error("Tried to construct uninitialised StaticConfig!");
        }
    }

    const T*
    operator -> () const
    {
        return &mConfig;
    }

private:

    friend class ConfigHandler;

    StaticConfig(const T& config)
    {
        mConfig = config;
        mIsInitialised = true;
    }

    static T mConfig;
    static bool mIsInitialised;
};

template <class T>
T StaticConfig<T>::mConfig;
template <class T>
bool StaticConfig<T>::mIsInitialised = false;

//ConfigHandler responsible for loading the data.
class ConfigHandler
{
public:

    ConfigHandler() :
        mFooConfig(GetFooConfig()),
        mBarConfig(GetBarConfig()),
        mSharedConfig(GetSharedConfig())
    {}

    FooConfig
    GetFooConfig()
    {
        FooConfig fooConfig;
        fooConfig.i = 1337;
        fooConfig.d = 123.45;
        return fooConfig;
    }

    BarConfig
    GetBarConfig()
    {
        BarConfig barConfig;
        barConfig.x = 69;
        barConfig.y = 987.65;
        return barConfig;
    }

    SharedConfig
    GetSharedConfig()
    {
        SharedConfig sharedConfig;
        sharedConfig.text = "This is a std::string!";
        return sharedConfig;
    }

private:

    StaticConfig<FooConfig> mFooConfig;
    StaticConfig<BarConfig> mBarConfig;
    StaticConfig<SharedConfig> mSharedConfig;
};

class Foo
{
public:

    void
    Print()
    {
        std::cout << "Foo prints " << mConfig->i << " " << mConfig->d << " "
                  << mSharedConfig->text << '\n';
    }

private:

    StaticConfig<FooConfig> mConfig;
    StaticConfig<SharedConfig> mSharedConfig;
};

class Bar
{
public:

    void
    Print()
    {
        std::cout << "Bar prints " << mConfig->x << " " << mConfig->y << " "
                  << mSharedConfig->text << '\n';
    }

private:

    StaticConfig<BarConfig> mConfig;
    StaticConfig<SharedConfig> mSharedConfig;
};

int main()
{
    //If uncommented, this next line throws as it attempts to...
    //...construct a StaticConfig<FooConfig> inside foo before...
    //...ConfigHandler has a chance to initialise things.
    //Foo aFoo;

    //ConfigHandler must only briefly exist to load data.
    ConfigHandler();
    Foo foo;
    Bar bar;

    foo.Print();
    bar.Print();

    return 0;
}
