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.
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
- arrays of void, references, functions, or of invalid size
- type member that is not a type
- pointers to references, references to references, references to void
- pointer to member of a non-class type
- invalid conversions of template value parameters
- function types with arguments of type void
- const/volatile function type
That's probably why in Boost documentation, there is:
Without some (as yet unspecified) help
from the compiler, ispod will never
report that a class or struct is a
POD; this is always safe, if possibly
sub-optimal. Currently (May 2005) only
MWCW 9 and Visual C++ 8 have the
necessary compiler-_intrinsics.
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
.
I'm not sure about the way you're trying to do SFINAE here, since is_pod<T>::test(...)
will match is_pod<T>::test(0)
too. Perhaps if you use a different type instead of 'int' you'd get a better match:
template <typename T> class is_pod
{
struct my_special_type { };
public:
typedef char Yes;
typedef struct {char a[2];} No;
template <typename C> static Yes test(my_special_type)
{
union {T validPodType;} u;
}
template <typename C> static No test(...)
{
}
enum {value = (sizeof(test<T>(my_special_type())) == sizeof(Yes))};
};
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.