Go Back   Rhinocerus > Newsgroup > Newsgroup comp.language.c++ > Newsgroup comp.language.c++.moderated

Reply
 
Thread Tools Display Modes
  #1 (permalink)  
Old 07-12-2012, 01:41 AM
Cassio Neri
Guest
 
Posts: n/a
Default Looking for a portable implementation of is_comparable

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! ]
Reply With Quote
Alt Today
Advertising
 
and become member of Rhinocerus
Standard Sponsored Links

  #2 (permalink)  
Old 07-12-2012, 08:09 PM
Howard Hinnant
Guest
 
Posts: n/a
Default Re: Looking for a portable implementation of is_comparable

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! ]
Reply With Quote
  #3 (permalink)  
Old 07-12-2012, 11:20 PM
Cassio Neri
Guest
 
Posts: n/a
Default Re: Looking for a portable implementation of is_comparable

> 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! ]
Reply With Quote
  #4 (permalink)  
Old 07-13-2012, 05:38 PM
Cassio Neri
Guest
 
Posts: n/a
Default Re: Looking for a portable implementation of is_comparable

> 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! ]
Reply With Quote
  #5 (permalink)  
Old 07-13-2012, 05:43 PM
Howard Hinnant
Guest
 
Posts: n/a
Default Re: Looking for a portable implementation of is_comparable

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! ]
Reply With Quote
  #6 (permalink)  
Old 07-14-2012, 02:24 AM
Cassio Neri
Guest
 
Posts: n/a
Default Re: Looking for a portable implementation of is_comparable

> 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! ]
Reply With Quote
 
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off




All times are GMT. The time now is 10:41 PM.


Copyright ©2009

LinkBacks Enabled by vBSEO 3.3.0 RC2 © 2009, Crawlability, Inc.