views:

132

answers:

1

I'm trying tow write a SFINAE template to determine whether two classes can be added together. This is mostly to better understand how SFINAE works, rather than for any particular "real world" reason.

So what I've come up with is

#include <assert.h>

struct Vec
{
  Vec operator+(Vec v );
};

template<typename T1, typename T2>
struct CanBeAdded
{
  struct One { char _[1]; };
  struct Two { char _[2]; };

  template<typename W>
  static W make();

  template<int i>
  struct force_int { typedef void* T; }; 

  static One test_sfinae( typename force_int< sizeof( make<T1>() + make<T2>() ) >::T );
  static Two test_sfinae( ... );

  enum { value = sizeof( test_sfinae( NULL ) )==1 };
};


int main()
{
  assert((CanBeAdded<int, int>::value));
  assert((CanBeAdded<int, char*>::value));
  assert((CanBeAdded<char*, int>::value));
  assert((CanBeAdded<Vec, Vec>::value));
  assert((CanBeAdded<char*, int*>::value));
}

This compiles for all except the last line, which gives

finae_test.cpp: In instantiation of ‘CanBeAdded<char*, int*>’:
sfinae_test.cpp:76:   instantiated from here
sfinae_test.cpp:40: error: invalid operands of types ‘char*’ and ‘int*’ to binary ‘operator+’

So this error is kind-of what I'd expect, but I'd expect the compiler to then find the test_sfinae( ... ) definition and use that instead (and not complain about the one that doesn't parse.

Clearly I'm missing something, I just don't know what it is.

+4  A: 

It looks to me like you've run into the problem that's discussed in Core Issue 339 as well as N2634. The bottom line is that you're pushing a bit beyond what any compiler can currently handle, even though what you're doing is allowed by the standard. C++ 0x will add more detail about what will and won't result in SFINAE failure versus a hard error. See N3000, §14.9.2, if you want to get into the gory details.

Jerry Coffin