C++ 隐式实例化变量模板的动态初始化顺序

C++ 隐式实例化变量模板的动态初始化顺序,c++,c++14,variable-templates,C++,C++14,Variable Templates,我提出了一个我认为是MSVC中的一个bug的问题,但结果证明是实现定义的行为。我想确保我完全理解原因。我把它放在一个翻译单元中: #include <limits> #include <utility> #include <type_traits> #include <cmath> #include <iostream> struct MyClass { double value_of; MyClass(double d):

我提出了一个我认为是MSVC中的一个bug的问题,但结果证明是实现定义的行为。我想确保我完全理解原因。我把它放在一个翻译单元中:

#include <limits>
#include <utility>
#include <type_traits>
#include <cmath>
#include <iostream>

struct MyClass {
  double value_of;
  MyClass(double d): value_of(d) {}
};

template<class T> struct MyTraits { static constexpr bool do_enable = false; };
template<> struct MyTraits<MyClass> { static constexpr bool do_enable = true; typedef double value_type; };

template<typename T> using EnableIfFP = std::enable_if_t<std::is_floating_point<T>::value>;
template<typename T> using EnableIfMyClass = std::enable_if_t<MyTraits<T>::do_enable>;

template<typename T> constexpr int EXP = std::numeric_limits<T>::max_exponent / 2;

template<typename T, typename Enabler = void> const T huge = T{ 0 };
template<typename T> const T huge<T, EnableIfFP<T> > = std::scalbn(1.0, EXP<T>);
template<typename T> const T huge<T, EnableIfMyClass<T> > = T{ huge<typename MyTraits<T>::value_type> };

int main() {
  // huge<double>; // PRESENCE OF THIS LINE AFFECTS OUTPUT IN MSVC
  std::cout << huge<MyClass>.value_of << std::endl;
  return 0;
}
#包括
#包括
#包括
#包括
#包括
结构MyClass{
双重价值;
MyClass(双d){
};
模板结构MyTraits{static constexpr bool do_enable=false;};
模板结构MyTraits{static constexpr bool do_enable=true;typedef double value_type;};
使用EnableIfFP=std::enable_if_t;
使用EnableIfMyClass=std::enable_if_t;
模板constexpr int EXP=std::数值限制::最大指数/2;
模板常数T=T{0};
模板常数T=std::scalbn(1.0,EXP);
模板常数T巨=T{巨};
int main(){
//巨大;//此行的存在会影响MSVC中的输出
标准::cout
  • 您是对的,“冲突”答案完全早于变量模板。(鉴于变量模板不是“全局变量”,且其实例化未在文本中定义(即声明),该语句仍然正确。)
  • 是的,
    std::scalbn
    成为constexpr将有助于(有时)无序的动态非局部初始化,并且如果变量模板(文本类型)的部分专门化是用常量表达式初始化的,不会发生这种动态初始化。很方便,它已被批准用于C++20,尽管它可能会或可能不会及时通过措辞审查
  • 无论是隐式实例化还是显式实例化,在这里都无济于事。正如您所引用的,只有显式专门化可以做到这一点,或者是在函数中隐藏内容的各种技巧。当然,您可以使用函数初始化变量(以及在变量初始化之前可能初始化的任何其他内容)并在其他地方使用变量

  • 仅供参考,你打破了clang 8.0.0 live:clang trunk是否编译它是否链接到不同编译单元中定义的未定义的因静态变量初始化顺序?@Myshkin这是一个单一的翻译单元,因此虽然它可能相关,但不是原因。启用链接时代码生成(LTCG,“整个程序优化”)“修复”它,这有点有趣。