|
|||
|
Hi.
I need a is_comparable meta-function similar to boost::has_greater. I can't use boost's due to some issues that I'll talk about later. A simplified version of my attempt follows: template <typename, typename = std::true_type> struct is_comparable : public std::false_type { }; template <typename T> struct is_comparable<T, typename std::is_convertible< decltype(T() > T()), bool >::type> : public std::true_type { }; Actually, I tried "std::declval<T>() < std::declval<T>()" inside decltype but that is an issues for MSVC 2010. (I'll go back to this point later.) For the time being, let's consider the version above regardless the need for T to be default constructible. For testing, I used this: struct Foo { bool operator >(const Foo&) const { return true; } }; int main() { using std::cout; using std::endl; using boost::has_greater; cout << std::boolalpha; cout << "Foo() > Foo() : " << (Foo() > Foo()) << endl; cout << "is_comparable<Foo>: " << is_comparable<Foo>::value << endl; cout << "has_greater<Foo> : " << has_greater<Foo>::value << endl; } With GCC 4.6.3 I have no surprises and get this output: Foo() > Foo() : true is_comparable<Foo>: true has_greater<Foo> : true Clang 3.1 fails to compile and complains about a supposedly missing closing parenthesis for decltype. Anyway, an extra pair of parenthesis fixes the issue: "decltype((T() > T()))". This way the code compiles and produces the same output as GCC. Funnily enough, if instead of ">" we use "<", i.e. ,"decltype(T() < T())", then Clang doesn't require the extra pair of parenthesis. This change doesn't affect GCC at all. What about MSVC 2010? The number of parenthesis and the choice of operator is irrelevant. The code compiles well but the result are different: Foo() > Foo() : true is_comparable<Foo>: false has_greater<Foo> : true So, for MSVC Foo isn't comparable. However, this changes if Foo implements "operator int()" (actually, just declaring it is enough for this). This inclusion doesn't affect GCC or Clang. Now, turning Foo into struct Foo { operator int() const { return 0; } }; makes has_greater (boost 1.49) failing to compile. The three compilers claim that the call to "operator >" is ambiguous and could be either the built-in "operator >(int, int)" or another for some boost type. After removing the call to has_greater the three compilers give: Foo() > Foo() : false is_comparable<Foo>: true Coming back to the issue with declval. MSVC 2010 doesn't provide the declaration and I initially thought that I could provide my oww based on the standard's with two simple modifications: (1) not putting it in namespace std and (2) removing noexcept (possibly replacing it with throw()), that is, template <class T> typename std::add_rvalue_reference<T>::type declval(); This seems to work fine but *not* in the implementation of is_comparable! MSVC complains about std::add_rvalue_reference: 1>is_comparable.cpp(15): error C2893: Failed to specialize function template 'std::add_rvalue_reference<_Ty>::type declval(void)' 1> With the following template arguments: 1> 'T' Apparently, MSVC fails to see T is a template parameter and considers it as a type. The obvious workaround (which can create other issues is) template <class T> T&& declval(); I want to double check with you if my interpretations are right, especially: 1) GCC is correct in all these points. 2) Clang is wrong when it requires the double parenthesis for > and it's right when it doesn't for <. 3) MSVC 2010 has two bugs: firstly, "is_comparable<Foo>" yields the wrong result in the absence "operator int()" (and all other implicit conversion operators) and, secondly, "std::add_rvalue_reference" doesn't work (perhaps only when combined with SFINAE and decltype). 4) The implementation of boost::has_greater has a bug. I would also strongly appreciate any help on implementing a preferable portable is_comparable or at least one that works for MSVC 2010 (then I can use the preprocessor to chose between different implementations). Cassio. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|
||||
|
||||
|
|
|
|||
|
On Jul 11, 9:41 pm, Cassio Neri <cassio.n...@gmail.com> wrote:
> 2) Clang is wrong when it requires the double parenthesis for > and it's > right when it doesn't for <. Do you have -std=c++11 turned on for clang? In C++03 mode decltype is emulated with a macro, which would explain the need for the double parenthesis. Howard -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
> Do you have -std=c++11 turned on for clang? In C++03 mode decltype is
> emulated with a macro, which would explain the need for the double > parenthesis. > > Howard I have previously tried with --std=c++0x and, after your reply, I tried -std=c++0x, --std=c++11 and -std=c++11. All options require the extra pair of parenthesis, otherwise I get this: is_comparable.cpp:20:18: error: expected ')' decltype(T() > T()), bool ^ is_comparable.cpp:20:13: note: to match this '(' decltype(T() > T()), bool ^ For reference, that's the complete command: $ clang -std=c++11 -o is_comparable is_comparable.cpp /usr/lib/gcc/x86_64-pc-linux-gnu/4.6.3/libstdc++.a Even, if it decltype were a macro, why would it require double parenthesis for decltype((T() > T())) but not for decltype(T() < T())? The situation is exactly the same with declval, that is, decltype((declval<T>() > declval<T>())) // requires double parenthesis decltype( declval<T>() < declval<T>() ) // works fine Out of curiosity, I've tried several other binary operators including some more "esoteric" ones (e.g. >>=) and > seems to be the that requires double parenthesis. Thanks for your reply. Cassio -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
> Out of curiosity, I've tried several other binary operators including
some > more "esoteric" ones (e.g. >==) and > seems to be the that requires double > parenthesis. I meant: ... " > seems to be the *only one* that requires double parenthesis." Regarding the problem with boost::has_greater, after my original post I discover that this is a fairly known and documented issue. Cassio. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
On Jul 12, 7:20 pm, Cassio Neri <cassio.n...@gmail.com> wrote:
> > Do you have -std=c++11 turned on for clang? In C++03 mode > > decltype is emulated with a macro, which would explain the need > > for the double parenthesis. > > > Howard > > I have previously tried with --std=c++0x and, after your reply, I > tried -std=c++0x, --std=c++11 and -std=c++11. All options require > the extra pair of parenthesis, otherwise I get this: > > is_comparable.cpp:20:18: error: expected ')' > decltype(T() > T()), bool > ^ > is_comparable.cpp:20:13: note: to match this '(' > decltype(T() > T()), bool > ^ > > For reference, that's the complete command: > > $ clang -std=c++11 -o is_comparable is_comparable.cpp > /usr/lib/gcc/x86_64-pc-linux-gnu/4.6.3/libstdc++.a > > Even, if it decltype were a macro, why would it require double > parenthesis for decltype((T() > T())) but not for decltype(T() < > T())? It turns out this is a very recently fixed bug in clang. http://lists.cs.uiuc.edu/pipermail/c...04/058564.html Howard -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
> It turns out this is a very recently fixed bug in clang.
> > http://lists.cs.uiuc.edu/pipermail/c...04/058564.html > > Howard That's good news! Unfortunately, the two MSVC bugs that I mentionned earlier are still present in MSVC 2012 RC. I've just reported them through Microsoft Connect. This is a bit annoying for me since I have to change my code and avoid using is_comparable altogheter. :-( -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|
![]() |
| Thread Tools | |
| Display Modes | |
|
|