【问题标题】:Test for existence of std::ostream operator<< via SFINAE GCC bug?通过 SFINAE GCC 错误测试 std::ostream operator<< 是否存在?
【发布时间】:2011-06-04 09:09:49
【问题描述】:

我决定亲自尝试编写 Substitution Failure Is Not A Error (SFINAE) 代码来测试是否为自定义类型定义了全局 operator&lt;&lt;

堆栈溢出问题 SFINAE + sizeof = detect if expression compiles 已经解决了通过 SFINAE 对运算符 &lt;&lt; 进行的测试,但我的代码略有不同并且产生了令人费解的结果。

具体来说,如果我尝试在test_ostr SFINAE 模板代码之后为我的自定义类型(结构 A)定义 operator&lt;&lt;,我的下面的测试代码甚至不会编译——但是,从我的理解它应该可以正常工作,因为它是在 test_ostr 类的任何实际实例化之前定义的。

OTOH,如果我为一个甚至没有实例化或定义的不同类定义operator&lt;&lt;,它编译。但是,test_ostr 代码无法正确找到operator&lt;&lt;

此代码在 GCC 4.4.3 中编译和运行:

//#define BUG 1 // Uncomment and the program will not compile in GCC 4.4.3
//#define BUG 2 // Uncomment and the program will compile, but produces an incorrect result, claiming operator<< is not defined for A.

#include <iostream>

struct A{};
struct B{};

// If BUG is #defined, the operator<< for struct A will be defined AFTER the test_ostr code
// and if BUG <=1, then GCC 4.4.3 will not compile with the error:
// sfinae_bug.cpp:28: error: template argument 2 is invalid
#ifdef BUG
// if BUG > 1, defining the opertor << for *C*, an un-defined type, will make GCC  magically compile!?
#  if BUG > 1
  struct C;
  std::ostream& operator<<(std::ostream&, const C&);
#  endif
#endif

#ifndef BUG
  std::ostream& operator<<(std::ostream& ostr, const A&) { return ostr; };
#endif

template<class T>
struct test_ostr
{
  template <class U, std::ostream& (*)(std::ostream&, const U&) >
  struct ostrfn;
  template<class U>
  static short sfinae(ostrfn<U, &operator<< >*);
  template<class U>
  static char  sfinae(...);
  enum { VALUE = sizeof(sfinae<T>(0)) - 1 };
};

#ifdef BUG
  std::ostream& operator<<(std::ostream& ostr, const A&) { return ostr; };
#endif

int main(void)
{
  std::cout << "std::ostream defined for A: " << int(test_ostr<A>::VALUE) << std::endl;
  std::cout << "std::ostream defined for B: " << int(test_ostr<B>::VALUE) << std::endl;
  return 0;
}

显示错误的输出:

>c++ sfinae_bug.cpp && ./a.out 
std::ostream defined for A: 1
std::ostream defined for B: 0

>c++ -DBUG sfinae_bug.cpp && ./a.out 
sfinae_bug.cpp:28: error: template argument 2 is invalid

>c++ -DBUG=2 sfinae_bug.cpp && ./a.out 
std::ostream defined for A: 0
std::ostream defined for B: 0

这些是编译器错误吗?我错过了什么吗?不同的编译器结果会不会不同?

【问题讨论】:

  • 仅供参考,VS2010 的对应结果为:1 0,错误,1 0

标签: c++ templates gcc metaprogramming sfinae


【解决方案1】:

这是错误的,因为operator&lt;&lt; 是一个非依赖名称。因此,对于没有operator&lt;&lt; 的情况,您的模板格式错误,编译器有权在模板定义时拒绝它。

template<class U>
static short sfinae(ostrfn<U, &operator<< >*);

SFINAE 适用于未声明从属名称时。

【讨论】:

  • 运算符
  • @McKay 没有为内置类型声明“操作符<< 运算符不是实际函数。我只能说,代码中operator&lt;&lt; 的非依赖查找不考虑仅在实例化时可见的函数声明。因此,在您的代码中定义 BUG 时,它应该给出编译器错误 (BUG 0 (BUG > 1) 回答。 (假设 sizeof(short) 是 2)。
猜你喜欢
  • 2020-07-12
  • 1970-01-01
  • 2013-07-28
  • 1970-01-01
  • 2020-08-18
  • 1970-01-01
  • 1970-01-01
  • 2023-03-21
  • 2021-12-17
相关资源
最近更新 更多