others - 通过typedef强制模板实例化: 在G 上成功,在Visual C 上失败

113 5

我想强制模板实例化,
下面的代码在g (http://coliru.stacked-crooked.com/a/33986d0e0d320ad4 )处运行(打印出1 ),
但是,它在Visual C (https://rextester.com/WGQG68063 )输出错误的结果(0 )。


#include <iostream>


#include <string>


template <int& T>struct NonTypeParameter { };



//internal implementation


int lala=0;


template <typename T> struct Holder{


 static int init;


};


template <typename T> int Holder<T>::init = lala++;



//tool for user 


template <typename T> struct InitCRTP{ 


 using dummy=NonTypeParameter<Holder<T>::init>;


};



class WantInit : public InitCRTP<WantInit>{};//user register easily


int main(){


 std::cout << lala << std::endl;


}



是Visual C++编译器错误,还是一种未定义的行为?
如果是Visual C 错误,如何解决它的?

时间: 原作者:

135 1

编译器错误,当然我们可以通过修改InitCRTP来验证它:


template <typename T, typename = NonTypeParameter<Holder<T>::init>>


struct InitCRTP {


};



引用InitCRTP这又应该强制Holder<T>::init的实例化,但是vs没有实例化

我们可以进一步验证,当用作基类时,成员函数声明与类一起被实例化:


template <typename T> struct InitCRTP{


 using dummy=NonTypeParameter<Holder<T>::init>;


 void dummy2(dummy);


};



尽管如此,VC还是出现了错误,鉴于Clang和GCC都表现出的行为,所以,这是一个VC错误。

原作者:
131 4

class WantInit : public InitCRTP<WantInit>不是实例化InitCRTP<WantInit>::dummy,也不是Holder<WantInit>::init,因为它们不是由程序中实际使用的某些东西引用的,代码中的隐式实例化链不需要实例化Holder<T>::init,请参见隐式实例化

这适用于类模板的成员: 除非该成员在程序中使用否则它不被实例化并且不需要定义。

修复是使用显式模板实例化


template struct Holder<void>;



这会导致Holder<void>与它的所有非模板成员一起被实例化。

或者,你也可以只实例化Holder<T>::init成员,例如:


static_cast<void>(Holder<void>::init);



原作者:
58 0

让我们试着确定ODR-use的成员。


#include <iostream>


#include <string>



int lala=0;


template <typename T> struct Holder{


 static int init;


};


template <typename T> int Holder<T>::init = lala++;



template <typename T> struct InitCRTP{


 InitCRTP() { (void)Holder<T>::init; }


};



class WantInit : public InitCRTP<WantInit>{};


int main(){


 std::cout << lala << std::endl;


 // WantInit w; <---------------------------- look here


}



现在,如果注释掉的行被注释掉,程序的结果就会改变。

原作者:
...