首页 > 解决方案 > 通过 typedef 强制模板实例化:g++ 成功,Visual C++ 失败

问题描述

我想强制模板实例化。
以下代码1在 g++ ( http://coliru.stacked-crooked.com/a/33986d0e0d320ad4 ) 上工作 (打印)。
但是,它会0在 Visual C++ ( https://rextester.com/WGQG68063 ) 上打印错误的结果 ( )。

#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++ 错误,如何解决它(同时仍然保持美观)?

编辑:按照 Max Langhof(和许多人)的建议更改类 -> 结构。感谢。

赏金原因

StoryTellerMaxim Egorushkin的相反解决方案以及他们的深入讨论(谢谢!),这听起来像是 C++ 规则的模糊区域。

如果是 Visual C++ 错误,我希望问题能够确定地报告。

此外,我仍然希望有一个很好的解决方法,因为这种技术对于自定义类型 ID 生成非常有用。显式实例化不是那么方便。

注意:我将赏金授予Kaenbyo Rin,因为对我来说,这很容易理解。
这并不意味着其余的答案不太正确或不太有用。
我仍然不确定哪个是正确的。读者应谨慎行事。
为了安全起见,我假设我只是不能使用该功能(目前)。感谢大家。

标签: c++visual-c++g++c++17template-instantiation

解决方案


当然,其中涉及编译器错误。我们可以通过改变InitCRTP一点来验证它:

template <typename T, typename = NonTypeParameter<Holder<T>::init>>
struct InitCRTP {
};

现在提到任何InitCRTP<T>特化都必须使用Holder<T>::init来确定第二个模板参数。这反过来应该强制实例化Holder<T>::init,但VS 不会实例化

一般来说,使用 CRTP 类作为基础应该已经实例化了类内的所有声明,包括dummy. 所以这也应该奏效。

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

template <typename T> struct InitCRTP{
    using dummy=NonTypeParameter<Holder<T>::init>;
    void dummy2(dummy);
};

尽管如此,VC++ 还是很顽固。鉴于所有这些,以及 Clang 和 GCC 所表现出的行为,这是一个 VC++ 错误。


推荐阅读