【发布时间】:2011-06-04 09:09:49
【问题描述】:
我决定亲自尝试编写 Substitution Failure Is Not A Error (SFINAE) 代码来测试是否为自定义类型定义了全局 operator<<。
堆栈溢出问题 SFINAE + sizeof = detect if expression compiles 已经解决了通过 SFINAE 对运算符 << 进行的测试,但我的代码略有不同并且产生了令人费解的结果。
具体来说,如果我尝试在test_ostr SFINAE 模板代码之后为我的自定义类型(结构 A)定义 operator<<,我的下面的测试代码甚至不会编译——但是,从我的理解它应该可以正常工作,因为它是在 test_ostr 类的任何实际实例化之前定义的。
OTOH,如果我为一个甚至没有实例化或定义的不同类定义operator<<,它将编译。但是,test_ostr 代码无法正确找到operator<<。
此代码在 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