This compiler bug vexes the linker with garbage, as best as I can track down the problem (VS2015 is new, no patches/updates have been released as of this writing). The crash happens in the linker. The compiler seems to think all went well.
When this bug is "excited", the problem is within the code which uses the generated template object. Put another way, even if you disable optimization in the header, but turn optimization back on in the body, it still crashes the linker. What "works" is to disable optimization on code which instantiates and uses member functions of the template object (you can leave optimization on for all code outside this target).
For example, in the code posted in the question, leave optimizations on throughout the headers. On the function which USES the template, do:
#pragma optimize( "", off )
void test()
{
two<one<int> > obj;
obj.func();
}
#pragma optimize( "", on )
This isolates the loss of optimization to that code which ignites the problem, and the linker succeeds.
Of course, the pragma's themselves can be wrapped with conditional defines, or some other mechanism, which you can disable once a patch to VS2015 is released that fixes the problem.
In this way the code can be used without concern for build configurations (meaning, it would work for both CMAKE building and IDE building) without having to burden subsequent users of the code (with anything more than a define to control whether or not optimization is disabled).
In case it happens to be practicable for your situation, you could also try something like:
template<typename T>
struct two
{
T t;
void func()
{
typedef typename T::type type;
type i = std::numeric_limits<type>::min();
type j = std::numeric_limits<type>::epsilon();
t.t1 = i / 2 + j;
t.t2 = t.t1;
}
};
This kind of restating the code bypasses the bug, and compiles without crashing the linker.
Also, this bypasses the problem, too:
void func()
{
typedef typename T::type type;
t.t1 = std::numeric_limits<type>::min() / 2 + std::numeric_limits<type>::epsilon();
t.t2 = t.t1;
}
Also, which is curious to me, and represents slightly better design (since it does not require one class to fiddle with the members of another)
template<typename T>
struct one
{
typedef T type;
T t1, t2;
void set( const T & i ) { t1 = t2 = i; }
};
template<typename T>
struct two
{
T t;
void func()
{
typedef typename T::type type;
t.set( std::numeric_limits<type>::min() / 2 + std::numeric_limits<type>::epsilon() );
}
};
The good news being that there IS a solution that doesn't involve changing the project build rules, leaves optimization enabled and is effectively identical.
It appears the culprit is actually the t.t1 = t.t2 = ...
clause. Why such an assignment triggers a linker crash, but equivalent expressions otherwise don't is a mystery for Microsoft to dive into, but really it appears the solution results in very slightly better looking code.