使用 SFINAE 检测 C++ 中类型的 POD 性;
这里原来的标题是 VS2005 C++ 中 SFINAE 错误的解决方法
这是暂时使用 SFINAE 来为 TR1 中存在的 is_pod 模板类创建等效项(在 VS2005 中还没有 TR1)。 当模板参数是 POD 类型(包括基本类型和由它们组成的结构)时,它的 value 成员应该为 true;当模板参数不是 POD 类型时(如非平凡的构造函数),它的 value 成员应该为 false。
template <typename T> class is_pod
{
public:
typedef char Yes;
typedef struct {char a[2];} No;
template <typename C> static Yes test(int)
{
union {T validPodType;} u;
}
template <typename C> static No test(...)
{
}
enum {value = (sizeof(test<T>(0)) == sizeof(Yes))};
};
class NonPOD
{
public:
NonPod(const NonPod &);
virtual ~NonPOD();
};
int main()
{
bool a = is_pod<char>::value;
bool b = is_pod<NonPOD>::value;
if (a)
printf("char is POD\n");
if (b)
printf("NonPOD is POD ?!?!?\n");
return 0;
}
问题是,VS 2005 不仅没有 TR1,它也不会关心上面的并集(当模板参数不是 POD 时,它不应该有效),因此 a 和 b 的计算结果都为 true。
感谢下面发布的答案。 仔细阅读它们(和代码)后,我意识到我想做的确实是一个错误的方法。 这个想法是将 SFINAE 行为与对模板 must_be_pod 的改编结合起来(我在《Imperfect C++》一书中找到了它,但也可以在其他地方找到它)。 实际上,这需要 SFINAE 制定一套非常特殊的规则,显然这不是标准定义的。 毕竟,这并不是 VS 中的一个真正的错误。
The original title here was
Workaround for SFINAE bug in VS2005 C++
This is tentative use of SFINAE to make the equivalent for the is_pod template class that exists in TR1 (In VS2005 there's no TR1 yet). It should have its value member true when the template parameter is a POD type (including primitive types and structs made of them) and false when it's not (like with non-trivial constructors).
template <typename T> class is_pod
{
public:
typedef char Yes;
typedef struct {char a[2];} No;
template <typename C> static Yes test(int)
{
union {T validPodType;} u;
}
template <typename C> static No test(...)
{
}
enum {value = (sizeof(test<T>(0)) == sizeof(Yes))};
};
class NonPOD
{
public:
NonPod(const NonPod &);
virtual ~NonPOD();
};
int main()
{
bool a = is_pod<char>::value;
bool b = is_pod<NonPOD>::value;
if (a)
printf("char is POD\n");
if (b)
printf("NonPOD is POD ?!?!?\n");
return 0;
}
The problem is, not only VS 2005 doesn't have TR1, it won't care about the union above (which shouldn't be valid when the template parameter is not a POD), so both a and b evaluate to true.
Thanks for the answers posted below. After reading carefully them (and the code) I realized that what I was trying to do was really a wrong approach. The idea was to combine SFINAE behavior with an adaptation to the template must_be_pod (which I found in the book Imperfect C++, but it can be found in another places, too). Actually, this would require a quite particular set of rules for SFINAE, which are not what the standard defines, obviously. This is not really a bug in VS, after all.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您的方法的最大问题是您在这里不执行 SFINAE - SFINAE 仅适用于此处的参数类型和返回类型。
然而,在标准中的所有 SFINAE 情况中,没有一个适用于您的情况。 它们是
这可能就是为什么在 Boost 文档中,有:
The biggest problem with your approach is you don't do SFINAE here - SFINAE only applies to parameter types and return type here.
However, of all the SFINAE situations in the standard, none applies to your situation. They are
That's probably why in Boost documentation, there is:
这也不适用于 VS2008,但我怀疑您也知道这一点。 SFINAE 用于推导模板参数的模板参数; 即使您可以创建与另一种类型不兼容的类型(即联合不能使用非 POD),您也无法真正推断出揭示类型构造函数的类型。
事实上,VS 2008 使用编译器对特征的支持来实现
std::tr1::type_traits
。This doesn't work with VS2008 either, but I suspect you knew that too. SFINAE is for deducing template arguments for template parameters; you can't really deduce the type of something that reveals the constructor-ness of a type, even though you can create a type that is incompatible with another type (i.e., unions can't use non-POD).
In fact, VS 2008 uses compiler support for traits to implement
std::tr1::type_traits
.我不确定你在这里尝试执行 SFINAE 的方式,因为
is_pod::test(...)
将匹配is_pod::test( 0) 也是如此。 也许如果您使用不同的类型而不是“int”,您会得到更好的匹配:
您可能还想查看 Boost.Enable_if 为您执行 SFINAE - 除非您尝试实现自己的库或出于某种原因。
I'm not sure about the way you're trying to do SFINAE here, since
is_pod<T>::test(...)
will matchis_pod<T>::test(0)
too. Perhaps if you use a different type instead of 'int' you'd get a better match:You might also want to look at Boost.Enable_if to do your SFINAE for you -- unless you're trying to implement your own library or for some reason.