不同编译器版本中constexpr评估的差异

时间:2016-01-02 01:05:53

标签: c++ templates c++11 gcc constexpr

我有以下程序:

constexpr int flag (int);

template<class Tag>
struct writer {
  friend constexpr int flag (Tag) {
    return 0;
  }
};

template<bool B, class Tag = int>
struct dependent_writer : writer<Tag> { };

template<
  bool B = noexcept (flag (0)),
  int    =   sizeof (dependent_writer<B>)
>
constexpr bool f () {
  return B;
}

int main () {
  constexpr bool a = f();
  constexpr bool b = f();

  static_assert( !a, "was not instantiated" );
  static_assert( !b, "was not instantiated" ); // here's the difference
}

有趣的是,这个程序用C ++ 11,C ++ 14和C ++ 17模式编译gcc 5.2和clang 3.6。但是,使用gcc 4.7,4.8和4.9会发生以下错误:

main.cpp: In function 'int main()':
main.cpp:26:7: error: static assertion failed: was not instantiated
       static_assert( !b, "was not instantiated" ); // here's the difference
       ^

似乎在旧的编译器中,模板函数f()的默认模板参数是在函数调用站点决定的。第一次调用f()时,模板类writer<int>最终被实例化,它定义了函数外部函数flag()。这会更改noexcept(flag(0))的值,因为编译器现在可以通过检查告诉该函数是noexcept,因为它找到了一个定义,第二次调用f()。因此,在第二次调用f()时,找到的模板参数是不同的。

另一方面,较新的编译器似乎在声明模板函数f()时决定默认模板参数,因此结果两次都相同。

这种以前的行为(gcc 4.7到4.9)对我来说有点奇怪。我想知道,如果这种行为是标准的符合,如果不符合,标准的哪一部分是矛盾的。

注意:问题Compile time template instantiation check有一个可接受的答案,它依赖于旧编译器的描述行为。因此,回答这个问题将有助于找出接受的解决方案是否正确。

0 个答案:

没有答案