This question is about the relationship between templates and static integral constants in Visual Studio C++ 2013 with flag /Za. It has implications for the boost library.
First, let us check the code without templates:
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;
}
According to the manual page for compiler option /Za: "Under the standard (/Za), you must make an out-of-class definition for data members". The example in that page and the code above declares the static constant within the class and specifies its value there. The need for the out of class definition is explained in this link.
Now, let us see the problem with templates.
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;
}
When compiling with /Za, the linker throws an error "LNK2019: unresolved external symbol". That error does not appear with option /Ze.The major problem is that some boost libraries use BOOST_STATIC_CONSTANT and BOOST_NO_INCLASS_MEMBER_INITIALIZATION in code similar to the above snipet.
Hacking some:
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;
}
This code now compiles with /Za.
Questions:
1) What does the C++11 standard say about templates and static integral constants? Can/must they have an out of class definition but their value be provided in the class definition?
2) Does boost have some workarounds?
UPDATE
It is important to keep the std::max
in the code because (I think) it tries to get the reference to its parameters. If one uses b_<a
then the compiler simply optimizes those constants away.