读书人

c++模板 SFINAE准则的疑惑

发布时间: 2013-04-20 19:43:01 作者: rapoo

c++模板 SFINAE原则的疑惑
最近在看《C+++Templates》 这本书,关于下面的例子有些疑惑,请各位高手帮忙解答下,谢谢
程序代码:

#include <iostream>

using namespace std;

template<typename T>
class IsClassT
{
private:
typedef char One;
typedef struct { char a[2]; } Two;

template<typename C> static One test(int C::*);
template<typename C> static Two test(...);

public:
enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 };
enum { No = !Yes };
};

class MyClass
{

};
template <typename T>
void check()
{
if (IsClassT<T>::Yes) {
std::cout << " IsClassT " << std::endl;
}
else {
std::cout << " !IsClassT " << std::endl;
}
}

int main()
{
std::cout << "int: ";
check<int>();

std::cout << "MyClass: ";
check<MyClass>();
}

这个是书上的源代码,但是在vs2008下编译不通过。


enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 };
enum { No = !Yes };
改为:
static bool isClass()
{
return sizeof(IsClassT<T>::test<T>(0)) == 1;
}
可以顺利通过
1 请问这是为什么?

2 template<typename C> static One test(int C::*); 中参数的类型为
指向int 型的C 类的成员的指针
但是MyClass 中并没有int型的数据成员,为什么可以通过编译,并且顺利得到结果?

3 template<typename C> static One test(int C::*); 为什么需要写成模板函数?
改写成:static One test(int T::*); 为什么不行??

谢谢大家帮忙解答下!
[解决办法]
1 请问这是为什么?
---------------------
VS在这里存在不符合C++标准的行为,微软做的IDE本来就不怎么样。
sizeof(IsClassT<T>::test<T>(0)) == 1
改为:
sizeof(test<T>(0)) == 1
就可以了。

2 template<typename C> static One test(int C::*); 中参数的类型为
指向int 型的C 类的成员的指针


但是MyClass 中并没有int型的数据成员,为什么可以通过编译,并且顺利得到结果?

int C::*不过是一种指针类型,与C内是否有这样的数据成员无关,就像即使没有定义int对象,但你依然可以定义int*指针道理一样。


3 template<typename C> static One test(int C::*); 为什么需要写成模板函数?
改写成:static One test(int T::*); 为什么不行??

因为SFINAE是模板推导规则,这个规则只有存在其它合法选择的情况下才有效,去掉template<typename C>后,另一个合法选择 template<typename C> static Two test(...);消失了,所以就成为了编译错误。
[解决办法]
其实 #1 说的很详细了。

引用:
这个还是有点疑惑,int C::*是一种指针类型,这个知道,但是指针也有指向的类型吧?
int C::* 与 double C::*应该是不一样的吧? 一个表示指向类C中的int型的数据成员,一个表示指向类C中
的double 型的数据成员。类C中都没有int型的数据成员,不明白为什么可以通过。
继续追问下,检测类C中是否有int型的数据成员,该怎么写呢?……

没有通用的方法检测某类是否存在 int 型数据成员。不过难点不在于如何检测某类某数据成员是否为 int 类型,而在于自动枚举某类所有数据成员,后者没有 c++ 支持的标准做法,如果想做的话,八成得使用编译器扩展。

引用:
是不是该这样理解,SFINAE是模板推导规则, 因为在一个类模板中
改写成:static One test(int T::*)后,通过IsClassT<int>::的形式来调用,
这个时候,static One test(int T::*)相当于 static One test(int int::*)没有使用模板推导?……

基本就是这样吧。
[解决办法]
引用:
谢谢楼上两位的解答,还有点疑惑
C/C++ code?12345678910111213class MyClass{public: int _a; double _b;}; void main(){ int MyClass::* p1 = &MyClass::_a; int MyClass::* p2 = &MyClass::_b……

int MyClass::* p1 = 0 ;
double MyClass::* p1 = 0 ;
都可以...

读书人网 >C++

热点推荐