当达到main()时,由全局变量的构造函数初始化的静态模板变量为空

时间:2015-11-15 05:03:18

标签: c++

请查看以下示例代码

template < typename TYPE >
struct foo
{
    static TYPE bar;
};

template < typename TYPE >
TYPE foo < TYPE >::bar;

template < typename RET, typename... ARGS >
struct changer
{
    typedef std::function < RET ( ARGS... ) > type;

    static void set ( type v ) { foo < type >::bar = v; }

    static type get () { return foo < type >::bar; }
};

void custom_func ( int i )
{
    std::cout << "called with " << i << std::endl;
}

struct initializer
{
    typedef changer < void, int > changer_t;

    initializer ()
    {
        changer_t::set ( std::bind ( & custom_func, std::placeholders::_1 ) );
        call ( 1 );
    }

    void call ( int v )
    {
        auto myfunc = changer_t::get ();

        if ( myfunc ) myfunc ( v );
        else std::cout << "myfunc is empty" << std::endl;
    }
};

initializer x;

int main()
{
    x.call ( 2 );

    return 0;
}

该程序的输出是

called with 1
myfunc is empty

当我将foochanger更改为非模板代码

struct foo
{
    static std::function < void ( int ) > bar;
};

std::function < void ( int ) > foo::bar;

struct changer
{
    typedef std::function < void ( int ) > type;

    static void set ( type v ) { foo::bar = v; }

    static type get () { return foo::bar; }
};

输出是我对第一个版本所期望的:

called with 1
called with 2

这里发生了什么?如何使其与模板化版本一起使用?

使用MSVC2013和g ++ templated |进行测试not-templated

更新:我只是意外地在VS中构建了发布模式,其中模板化版本输出

called with 1
called with 2

......我在挠痒UB吗?

1 个答案:

答案 0 :(得分:0)

模板的静态成员具有无序初始化。这意味着bar可能(但也可能不会)在初始化x之后为您的目的初始化太晚。

(对于非模板,情况并非如此,这就是为什么这种情况适合你的原因。)

另见Initialization order of static data inside class template