0

On the book C++ templates - The Complete Guide, Vandevoorde & Josuttis, it was suggested the following snippet to determine whether a type is a class or not. The argument was: "For class types we can rely on the observation that the pointer to member type construct int C::* is valid only if C is a class type" as a strategy to decide whether a type is a "class" type or not.

I have two questions:

1) Do you think the argument is valid? 2) How would you modify (preserving the strategy) the snippet below to make it work, since it doesn't compile on MSVC2013?

using namespace std;

template<typename T>
class IsClass
{
    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(IsClass<T>::test<T>(0) == 1)) };
};

class C{};

void main()
{
    if (IsClass<C>::YES)
        std::cout << "C Is a Class" << endl;
}
user2286810
  • 136
  • 9
  • MSVS 2013 only has partial SFINAE support. You might need to pick up MSVS 2015. – NathanOliver Jan 15 '16 at 15:14
  • 2
    I know this is "argument from authority" but if either one of those authors make a claim about C++ I would want strong evidence (chapter and verse from the standard) to contradict it. Specifically, if either of them disagreed with Bjarne Stroustrup about what the standard specified, I wouldn't want to place bets on who was right. With both of them having reviewed the code, it will be right. – Martin Bonner supports Monica Jan 15 '16 at 15:32
  • 1
    [Partial Support for Expression SFINAE in VS 2015 Update 1](http://blogs.msdn.com/b/vcblog/archive/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1.aspx). In 2013 version substitution failure IS an error. I do not see a workaround. – zdf Jan 15 '16 at 16:43
  • 1
    @NathanOliver: Even MSVC 2015 only has partial SFINAE support. They're throwing away the compiler and starting over. [Here's one of their blog posts about it](http://blogs.msdn.com/b/vcblog/archive/2015/09/25/rejuvenating-the-microsoft-c-c-compiler.aspx) – AndyG Jan 15 '16 at 18:30
  • @AndyG Thanks for the link. I didn't know they were redoing it. – NathanOliver Jan 15 '16 at 18:41
  • @NathanOliver This isn't expression SFINAE, though. This is original recipe SFINAE. – T.C. Jan 18 '16 at 00:00

1 Answers1

0

Contrary to the comments, your problem has nothing to do with expression SFINAE. This is bog-standard original-recipe SFINAE: you are checking the well-formedness of the type int C::*.

Before we start, you are parenthesizing it wrong. You want to apply sizeof to the result of test, not ==:

enum { YES = (sizeof(IsClass<T>::test<T>(0)) == 1) };
             //     ^                      ^

(Also, get rid of void main().)

Now, MSVC 2013 for some reason tries to do deduction and ignores the specified template argument if you do a qualified call:

    IsClass<T>::test<T>(0)
//  ^^^^^^^^^^^^

which is clearly a bug. I'm not sure why it's behaving this way, but then large parts of MSVC's frontend are held together by duct tape, so I'm not really surprised.

You don't need a qualified call anyway. Just write test<T>(0) and do an unqualified call:

enum { YES = (sizeof(test<T>(0)) == 1) };

which works on my MSVC 2013.

Community
  • 1
  • 1
T.C.
  • 133,968
  • 17
  • 288
  • 421