C++模板静态整数常量:出类定义

Hec*_*tor 9 templates boost initialization static-members c++11

这个问题是关于模板和Visual Studio C++ 2013中带有flag/Za的静态积分常量之间的关系.它对boost库有影响.


首先,让我们检查没有模板的代码:

struct easy
{
    static const int a = 5;
    const int b;

    easy( int b_ ) : b( std::max( b_, a ) )
    {}
};

const int easy::a;

int main()
{
    easy d_Easy( 0 );
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

根据编译器选项/ Za的手册页:"在标准(/ Za)下,您必须为数据成员制定一个类外定义".该页面中的示例和上面的代码声明了类中的静态常量,并在那里指定了它的值.在此链接中解释了对类外定义的需求.


现在,让我们看看模板的问题.

template< class T >
struct problem
{
    static const int a = 5;
    const int b;

    problem( int b_ ) : b( std::max( b_, a ) )
    {}
};

template< class T >
const int problem< T >::a;

int main()
{
    problem< char > d_Bad( 666 );
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

使用/ Za进行编译时,链接器会抛出错误"LNK2019:未解析的外部符号".选项/Ze不会出现该错误.主要问题是某些boost库在类似于上述snipet的代码中使用BOOST_STATIC_CONSTANT和BOOST_NO_INCLASS_MEMBER_INITIALIZATION.


黑客一些:

template< class T >
struct fixed
{
    static const int a;
    const int b;

    fixed( int b_ ) : b( std::max( b_, a ) )
    {}
};

template< class T >
const int fixed< T >::a = 5;

int main()
{
    fixed< char > d_Good( 777 );
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

此代码现在与/ Za编译.

问题:

1)C++ 11标准对模板和静态积分常数有何看法?可以/必须具有类外定义但它们的值是否在类定义中提供?

2)boost有一些解决方法吗?


UPDATE

保持std::max代码是很重要的,因为(我认为)它试图获取对其参数的引用.如果使用,b_<a那么编译器只是优化那些常量.

Col*_*mbo 6

首先,类中静态数据成员的声明永远不是定义.如果你使用那个变量,那么必须出现一个定义 - 当然是在课外.

std::max确实是odr-use a,因为它的参数是引用,如果引用绑定到它们([basic.def.odr]/3),变量就会被使用.(这确实是一个问题max- 它不应该使用a,实际上.)
在@ sehe的答案中,他直接使用三元运算符,避免了使用odr,因为左值和右值变换立即应用并产生一个恒定的表达.

  1. 这很简单.当需要定义类模板的静态数据成员时,即当该成员在您的情况下使用时,将实例化(命名空间作用域)定义.[temp.inst]/2:

    除非已显式实例化或明确专门化类模板或成员模板的成员,否则在需要成员定义存在的上下文中引用特化时,将隐式实例化成员的特化 ; 特别是,除非静态数据成员本身以需要静态数据成员的定义存在的方式使用,否则不会发生静态数据成员的初始化(以及任何相关的副作用).

    而且定义完全按照你的方式完成.[temp.static]/1:

    可以在包含静态成员的类模板的定义的命名空间范围中提供静态数据成员或静态数据成员模板的定义.

    [ 例如:

    template<class T> class X {
        static T s;
    };
    template<class T> T X<T>::s = 0;
    
    Run Code Online (Sandbox Code Playgroud)

    当成员是const整数类型时,初始化程序可以在类声明中提供,但这不会影响ODR在这方面的语义.仍然需要以相同的方式定义该定义,并按照您的方式编写.

因此,您看到的只是一个VC++错误.