0

I've been investigating the use of some judicious static assertions to improve error messages. Here's an example:

#include <type_traits> template<typename T> struct is_less_than_comparable { template<typename Test> static char test(decltype(*static_cast<Test*>(nullptr) < *static_cast<Test*>(nullptr))); template<typename Test> static int test(...); static const bool value = std::is_same<char, decltype(test<T>(true))>::value; }; template<typename K, typename V> class map { public: static_assert(is_less_than_comparable<K>::value, "Key type must be less-than comparable!"); }; struct x {}; int main() { map<x, int> intmap; } 

IDEONE will happily reject this code with the nice, clean error message I was hoping to get (once you replace nullptr with 0, anyway). But MSVC will not fire the static assertion and compiles this code just fine- even if I add some member functions and start calling on them.

4
  • The code isn't compiling for me. Are some additional header files needed? Commented Jun 9, 2011 at 22:58
  • I think this is related to VC++ not performing two-phase lookup of template dependent arguments. Commented Jun 9, 2011 at 23:28
  • @BenVoigt : My impression is that VC++ 2010 is just flat out broken when trying to use decltype for SFINAE. I've given up on attempting to use it at all :-[ Commented Jun 10, 2011 at 1:03
  • You should check out the recently added operator traits to Boost.TypeTraits Commented Nov 16, 2011 at 22:43

2 Answers 2

1

The problem is with VC++ 2010 handling of the metafunction is_less_than_comparable, not with static_assert.

If you change the code to:

static const bool value = std::is_same<double, decltype(test<T>(true))>::value; 

Then it will be false regardless of which overload is picked. The assertion then fires.

Evidently the wrong overload is being selected, SFINAE isn't removing the candidate with char return type.


Simpler test (incorrectly prints 1):

#include <type_traits> template<typename T> struct is_less_than_comparable { template<typename Test> static char test(decltype(*static_cast<Test*>(nullptr) < *static_cast<Test*>(nullptr)) b); template<typename Test> static int test(...); static const bool value = std::is_same<char, decltype(test<T>(true))>::value; }; struct x {}; #include <iostream> int main() { std::cout << is_less_than_comparable<x>::value << std::endl; } 

The compiler is, for no apparent reason, providing a bool operator<(x, x) operator, thus generating int is_less_than_comparable<T>::test<T>(bool). If a user-defined comparison operator is provided, its return type is correctly picked up. This operator isn't coming in with one of the headers, I can repro the decltype resolving to bool with no headers included.

This generates the proper error:

decltype(*(x*)nullptr < *(x*)nullptr) b; error C2676: binary '<' : 'x' does not define this operator or a conversion to a type acceptable to the predefined operator 

I think this is related to VC++ not performing two-phase lookup of template dependent arguments.

Sign up to request clarification or add additional context in comments.

Comments

1

I'm not certain what you're looking for in an answer here, so here's a type trait that works fine in VC++ 2010:

#include <type_traits> namespace supports { namespace details { struct return_t { }; template<typename T> static T& make(); } template<typename T> details::return_t operator <(T const&, T const&); template<typename T> struct less_than : std::integral_constant< bool, !std::is_same< decltype(details::make<T>() < details::make<T>()), details::return_t >::value > { }; } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.