Templates C++;模板静态整数常量:类外定义 这个问题是关于VisualStudioC++ 2013中的模板与静态积分常数之间的关系。它对boost库有影响
首先,让我们检查没有模板的代码:Templates C++;模板静态整数常量:类外定义 这个问题是关于VisualStudioC++ 2013中的模板与静态积分常数之间的关系。它对boost库有影响,templates,c++11,boost,initialization,static-members,Templates,C++11,Boost,Initialization,Static Members,首先,让我们检查没有模板的代码: 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; } 根据手册页面:“在标准(/Za)下,必须为数据成员进行类外定义”。该页面中的示例和上面的代码
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;
}
根据手册页面:“在标准(/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;
}
模板
结构问题
{
静态常数INTA=5;
常数int b;
问题(intb_uub):b(std::max(b_uua))
{}
};
模板
常数整数问题::a;
int main()
{
问题d_Bad(666);
返回0;
}
使用/Za编译时,链接器抛出错误“LNK2019:未解析的外部符号”。选项/Ze中不会出现该错误。主要问题是某些boost库在类似于上述snipet的代码中使用boost_STATIC_常量和boost_NO_INCLASS_MEMBER_初始化
黑客攻击:
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;
}
模板
结构固定
{
静态常数INTA;
常数int b;
固定(整数b_uub):b(标准::最大值(b_uua))
{}
};
模板
固定常数:a=5;
int main()
{
固定d_良好(777);
返回0;
}
此代码现在使用/Za进行编译
问题:
1) 关于模板和静态积分常数,C++11标准怎么说?它们是否可以/必须具有类外定义,但其值必须在类定义中提供
2) boost是否有一些变通方法
更新
在代码中保留
std::max
是很重要的,因为(我认为)它试图获取对其参数的引用。如果使用b_p>一个我使用了很长时间并且最近在c++11中变得更有用的变通方法:
struct easy
{
enum : int { a = 5 };
int b;
constexpr easy(int b_) : b(b_<a? a : b_)
{}
};
当然,它仅限于(用户定义/原语)整数类型
外部定义的常量的好处是,它们实际上可以通过重新编译定义值的转换单元来更改
首先,类中静态数据成员的声明从来不是定义如果您使用该变量,则必须提供定义-当然是课外定义
std::max
odr确实使用了a
,因为它的参数是引用,而变量是odr,如果引用绑定到它们([basic.def.odr]/3)。(这确实是max
的问题-它不应该使用a
,真的。)
在@sehe的回答中,他直接使用了三元运算符,避免了odr的使用,因为左值到右值的转换会立即应用,并产生一个常量表达式
这很简单。当需要类模板的静态数据成员的定义时,即当该成员在您的案例中使用odr时,将实例化(命名空间范围)定义。[临时安装]/2:
除非类模板或成员模板的成员已
显式实例化或显式专门化,专门化
当指定专门化时,隐式实例化成员的
在要求成员定义存在的上下文中引用;
特别是初始化(以及任何相关的副作用)
除非静态数据成员
本身的使用方式需要定义静态
数据成员必须存在
这个定义和你做的完全一样。[温度静态]/1:
静态数据成员或静态数据成员模板的定义
可以在包含
静态成员的类模板
[示例:
模板类X{
静态T-s;
};
模板tx::s=0;
当成员是const
integral类型时,可以在类中的声明中提供初始值设定项,但这并不影响ODR在这方面的语义。定义仍然需要以相同的方式提供,编写方式与您所做的相同
因此,您看到的似乎只是一个VC++错误。如果要指定基础类型,您不需要枚举类吗?@vsoftco否(至少在我的编译器上不需要)@vsoftco:类
部分使其成为强类型。没有它,声明会溢出到容器结构中。警告:作用域枚举仅在-std=c++11或-std=gnu++11
中可用,如果使用g++-pedantic
编译,我认为它应该是无关的:vs.vs.vs.vs.vs.vs.vs在生成的代码中,数据段中存在/不存在easy::a
。"如果有人使用b_,也许我的答案后面的一段对你真正的问题很重要?如果是这样,显然你总是需要将静态成员初始化分离到一个单独的转换单元中。@sehe:这是相关的,因为我无法在Visual Studio C++13中用/Za编译boost::pool。我将罪魁祸首追溯到问题中的行为太长了,读不下去了,我会告诉谁是负责人,我会向Boost人或FELAS女士报告bug。我已经发布了一个几乎详尽的TL比较。DI是正确的:没关系。编译器在代码中引用了<代码>:STD::MAX//CARD>变体(同样应该)。@谢:谢谢。你所做的证明了该页面中的编译器没有显示错误。但是,这些编译器没有问题:#include struct A{static const int A=5;A(){std::cout“std::max确实odr使用了A,因为它的参数是引用”你确定这足以需要定义吗?啊,似乎不是
struct Container
{
enum special_position : size_t { npos = size_t(-1), at_bof = 0 };
};
template<class T> class X {
static T s;
};
template<class T> T X<T>::s = 0;