This question already has answers here:
Print any c++11 array with a non-member ostream-overloaded function
(3 answers)
Closed 2 months ago.
I cannot compile with g++ a simple code that works perfectly in MSVC.
The code involves operator overload for ostream << array<T,D>, and g++ cannot find it, even though it's right here. Wherein the similar overload for ostream << vector doesn't cause any problem for g++.
A demo:
#include <iostream>
#include <vector>
#include <array>
template <class T> inline std::ostream& operator << (std::ostream& os, std::vector<T> &v) {
const int D = v.size();
os << "[";
if (D > 0) os << v[0];
for (int i = 1; i < D; i++) os << "," << v[i];
os << "]";
return os;
};
template <class T, int D> std::ostream& operator << (std::ostream& os, std::array<T, D> &a) {
os << "[";
if (D > 0) os << a[0];
for (int i = 1; i < D; i++) os << "," << a[i];
os << "]";
return os;
};
int main() {
std::vector<double> v = {1,2,3,4};
std::cout << v << std::endl;
//std::array<double, 2> a = { 1,2 }; <-- this lines won't compile in g++
//std::cout << a << std::endl;
return 0;
}
The commented lines cause g++ to spit a huge list of complains, starting with
test.cpp:33:12: error: no match for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'std::array<double, 2>')
33 | std::cout << a << std::endl;
| ~~~~~~~~~ ^~ ~
| | |
| | std::array<double, 2>
| std::ostream {aka std::basic_ostream<char>}
and ending with
ostream:691:5: error: no type named 'type' in 'struct std::enable_if<false, std::basic_ostream<char>&>'
The g++ version is
g++.exe (Rev2, Built by MSYS2 project) 9.2.0
Copyright (C) 2019 Free Software Foundation, Inc.
The same story is with other operators, but I left only the essential part.
Why is that and how to solve?
I need the code compiled by g++, because in has __float128.
And I need the templates, because it's a part of generalized algorithm.
Please note that I'm new to C++.
I searched for similar cases but didn't any, at least not something helpful.
The non-type template argument of std::array is of type size_t not int.
I am not sure which compiler is right here, but gcc accepts the code if you fix that:
template <class T, size_t D> std::ostream& operator << (std::ostream& os, std::array<T, D> &a) {
os << "[";
if (D > 0) os << a[0];
for (int i = 1; i < D; i++) os << "," << a[i];
os << "]";
return os;
};
Complete Example
PS: Note that overloading << for types you do not own comes with certain caveats. A function template template <typename T,size_t D> void print(const std::array<T,D>&) can do the printing as well.
The problem is that the non-type parameter D in your overloaded version is of type int instead of std::size_t.
To solve this you can change the non-type parameter D to be of type size_t instead of int as shown below:
//-----------------vvvvvvvvvvv---->changed int to std::size_t
template <class T, std::size_t D> std::ostream& operator << (std::ostream& os, std::array<T, D> &a) {
os << "[";
if (D > 0) os << a[0];
for (int i = 1; i < D; i++) os << "," << a[i];
os << "]";
return os;
};
int main() {
std::array<double, 2> a = { 1,2 };
std::cout << a << std::endl; //works with all compiler now
return 0;
}
Working demo
Related
I am trying to develop a class that has to be templated and needs to have some templated methods. I have been looking and, most likely because I do not know how to explain my problem, I have not been able to find the solution. Here is my exmaple:
template<typename T>
class TestClass{
public:
template<typename M>
TestClass(M val): val_(T(val)){}
template<typename N>
N func() {
return N(val_);
}
T get() {
return val_;
}
template<typename N>
N add(N val) {
return N(val_) + val;
}
private:
T val_;
};
This class will be called in templated functions such as this one:
template<typename T>
std::string str(TestClass<T> f)
{
std::ostringstream out;
out << f.func<T>();
out << "\n";
out << "get: ";
out << f.get();
out << "\n";
out << f.add<T>(0.0);
return out.str();
}
An here is an example of usage:
int main(int argc, char** argv){
TestClass<double> t('a');
std::cout<<"Manual output: \n";
std::cout<<"func: "<<t.func<double>()<<std::endl;
std::cout<<"get: "<<t.get()<<std::endl;
std::cout<<"add: "<<t.add<double>(0)<<std::endl;
std::cout<<"operator<< output: \n";
std::cout<<str(t)<<std::endl;
return 0;
}
I have compiled whithout std::string str(TestClass<T> f) function and its usage within the main and I observe the desired behaberou. However, I cannot compile this code with the following error:
error: expected primary-expression before '>' token
out << f.func<T>();
^
expected primary-expression before ')' token
out << f.func<T>();
^
expected primary-expression before '>' token
out << f.add<T>(0.0);
^
The compiler also produces errors regarding the << operator and the fact that f.func<T>() and f.add<T> type has not been resolved. If I remove the templated parts in the calls within str():
template<typename T>
std::string str(TestClass<T> f)
{
std::ostringstream out;
out << f.func();
out << "\n";
out << "get: ";
out << f.get();
out << "\n";
out << f.add(0.0);
return out.str();
}
Then, the compiler error is:
no matching function for call to 'TestClass<double>::func()'
out << f.func();
^
candidate is:template<class N> N TestClass<T>::func() [with N = N; T = double]
N func() {
^
couldn't deduce template parameter 'N'
out << f.func();
^
Which make sense because func() type can not be deduced. Also I have tryied, using f.func<T>() and f.add(0.0) but the error is simillar to the first one.
My question is: How should I do it so the compiler can do its job?
The func template member function must be labeled as a template function when called:
f.template func<T>();
The template keyword is required to indicate the left angle bracket < is NOT a less-than operator. See this explanation of this use of the template keyword.
The add member function picks up its template type from the parameter:
f.add(0.0); // typename N = double
//template.h using MSVC++ 2010
#pragma once
#include <iostream>
using std::ostream;
template <typename T, typename U> class Pair {
private:
T first;
U second;
public:
// Pair() ;
Pair ( T x = T() , U y = U() ) ;
template<typename T, typename U>
friend ostream& operator<< ( ostream& thisPair, Pair<T, U>& otherPair );
};
template <typename T, typename U>
Pair<T, U>::Pair ( T x , U y ) : first ( T ( x ) ), second ( U ( y ) )
{cout << x << y;}
template <typename T, typename U>
ostream& operator<< ( ostream& os, Pair<T, U>& otherPair )
{
os << "First: " << otherPair.first
<< " "<< "Second: " << otherPair.second << endl;
return os;
}
//template.cpp
int main()
{
int a = 5, b = 6;
Pair<int,int> pair4();
Pair<int, int> pair1 ( a, b );
cout<<pair4;
cout<<pair1;
return 0;
}
How to make a constructor or a member function to take default value?
The code above is giving linker error for pair4 when using cout statement.
The code works perfectly when cout<<pair4(); is commented.
I am trying to mimic a constructor taking 0,1 or 2 argument using a single default constructor in a template class.
Apart from other errors like shadowing template parameters (which MSVC++ wrongly ignores), the problem is here:
Pair<int,int> pair4();
This declares a function instead of a variable. This is because it can be syntactically both and C++ standard selects the most vexing parse: anything that can be interpreted by compiler as a declaration, will be interpreted as a declaration. The linker error then is that you try to print to cout address of a function that is never defined (has no address).
Side note: in GCC and Clang, you can actually link this because the address is immediatelly converted to bool for operator << (there is no operator for printing function pointers to ostream and bool is the only available implicit conversion) which will always result in true (address of a declared function can never be nullptr) so the address itself is optimized away.
The fix is very simple:
Pair<int,int> pair4;
I have a template function like this one
#include <list>
#include <iostream>
template<typename T>
std::ostream& operator<<(std::ostream& out, const std::list<T>& list){
out << "[";
if(!list.empty()){
typename std::list<T>::const_iterator it = list.cbegin();
out << *it;
for (++it; it != list.cend(); ++it){
out << ", ";
out << *it;
}
}
out << "]";
return out;
}
And some template class with nested classes
namespace my{
template<
typename T,
typename U = size_t
>
class graph{
public:
typedef T dist_t;
typedef U node_t;
class node_pt;
typedef struct arc_t{
node_pt* from = nullptr;
node_pt* to = nullptr;
dist_t weight;
} arc_t;
typedef struct arc_pt{
arc_t arc;
} arc_pt;
typedef struct node_pt{
node_t node;
} node_pt;
class arc_iterator{
public:
arc_pt* pt = nullptr;
public:
arc_pt* operator->() const{
return pt;
}
friend std::ostream& operator<< (std::ostream &out, const arc_iterator& it) {
out << "(" << it->arc.from->node << "," << it->arc.to->node << "," << it->arc.weight << ")";
return out;
}
};
class node_iterator{
public:
node_pt* pt = nullptr;
public:
node_t operator *() const{
return pt->node;
}
friend std::ostream& operator<< (std::ostream &out, const node_iterator& it) {
out << *it;
return out;
}
};
};
}
Some code to reproduce the problem
namespace my{
namespace test{
void run(){
typedef my::graph<size_t> graph_t;
std::list<graph_t::node_t> l1;
std::list<graph_t::dist_t> l2;
std::list<graph_t::node_iterator> l3;
std::list<graph_t::arc_iterator> l4;
std::cout << l1 << std::endl;
std::cout << l2 << std::endl;
std::cout << l3 << std::endl;
std::cout << l4 << std::endl;
}
}
}
int main(){
my::test::run();
}
The problem is it doesn't compile if I define the two friend methods. If I only define one method and comment one of the iterator list printing it works.
The error I'm getting is
src/OTest_Graph.cpp: In member function ‘virtual void my::test::TestGraph::run()’:
src/OTest_Graph.cpp:59:53: error: cannot bind ‘std::basic_ostream<char>’ lvalue to ‘std::basic_ostream<char>&&’
In file included from /usr/include/c++/4.7/iostream:40:0,
from h/OTest_Graph.h:4,
from src/OTest_Graph.cpp:1:
/usr/include/c++/4.7/ostream:600:5: error: initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = std::list<my::graph<long unsigned int>::node_iterator, std::allocator<my::graph<long unsigned int>::node_iterator> >]’
Can anyone tell me what's going on here?
Well, the code compiles and runs for me in clang++. Can't try with g++ on this computer.
Edit: Actually, it compiles with g++ as well, which makes sense because you only use the operator<< in the main which is in the global namespace. I assume your actual code is different \Edit
But I'm familiar with the "ostream lvalue can't bind to ostream&&" error
How to explain. There is a problem in providing operator<< between ostreams and any std class (like list in your example, but I found it with vector)
Mostly it works, but when the operator is called from a namespace (like your my namespace) it breaks.
Why? Because "where do I look for this operator<< member"? See, there might be a lot of operator<< between ostreams and lists - each in a different namespace. So where does the compiler look for it?
It looks in the namespaces of each on its operands (in your case - both are from std). And sometimes in the namespace of the caller (which in your case is my).
I say "sometimes" because according to the standard it shouldn't, but g++ does it anyway. clang++ doesn't - but looks in the global namespace instead (hence why it worked for me)
Ideally, you'd want to put the operator<< inside the std namespace (try it - it will work). BUT - that is against the standard. You are not allowed to do that. You can put it in the my namespace and it should work find in g++, but not in other compilers.
It's a problem. I "solved" it by creating a wrapper - a class that exists in my own namespace and only holds a reference to the std class - and can be printed.
template<class T> struct OutList<T>{
const std::list<T> &lst;
OutList(const std::list &l):lst(l){}
};
template<class T> OutList<T> outlist(const std::list<T> &lst){return OutList<T>(lst);}
std::ostream &operator<<(std::stream &out,const OutList<T> &lst){...}
....
std::cout << "list= "<<outlist(list)<<std::endl;
It isn't pretty, but that's all I found...
I had the same problem with the following operator, declared in the global namespace:
template <typename T>
std::ostream & operator << (std::ostream &os, const std::vector<T> &vector);
…when called from a function declared in a named namespace:
std::ostream & operator << (std::ostream &os, const Foo &foo) {
return os << foo.items; // error
}
…where Foo::items is a std::vector.
g++ gives the infamous error:
error: cannot bind 'std::basic_ostream<char>' lvalue to 'std::basic_ostream<char>&&'
The error arises because C++11 introduced a catch-all std::operator << template, which the comment in <ostream> describes as a "generic inserter for rvalue stream." The compiler does not find the global ::operator << template because argument-dependent lookup finds the std::operator << template first.
A simple and correct fix is to bring the global operator into the local scope by a using declaration:
std::ostream & operator << (std::ostream &os, const Foo &foo) {
using ::operator <<;
return os << foo.items; // OK
}
The error depends on the version of the standard library, see #matt-whitlock's answer.
A solution for g++ 4.7 :
Instead of
std::cout << l1 << std::endl;
std::cout << l2 << std::endl;
std::cout << l3 << std::endl;
std::cout << l4 << std::endl;
use
::operator<<(std::cout, l1) << std::endl;
::operator<<(std::cout, l2) << std::endl;
::operator<<(std::cout, l3) << std::endl;
::operator<<(std::cout, l4) << std::endl;
In the sample code below, it shows that boost::tuple can be created implicitly from the first template argument.
Because of that I am not able to write a << operator as it becomes ambiguous.
Also I don't understand why ostringstream& << float is also ambiguous. This does not have any implicit construction. Why does this also give ambiguous error?
#include <iostream>
#include <boost/tuple/tuple.hpp>
#include <sstream>
#include <string>
using namespace std;
class Myclass
{
};
typedef boost::tuple<int,float,Myclass> Mytuple;
ostringstream& operator<<(ostringstream& os_, Mytuple tuple_)
{
float f = tuple_.get<1>();
//os_ << (int)tuple_.get<0>(); // Error because int is implicitly converted into Mytuple. WHYY?
//os_ << tuple_.get<1>(); // No Clue Why this is ambiguous.
//os_ << tuple_.get<2>(); // Error because no matching operator. Fine.
return os_;
}
int main()
{
Mytuple t1;
t1 = 3; // Working because int is implicitly converted into Mytuple!! WHY?
//t1 = 3.0f; // Error because no matching constructor. Fine.
return 0;
}
Error Mesasge:
tupleTest2.C:18: error: ISO C++ says that these are ambiguous, even
though the worst conversion for the first is better than the worst
conversion for the second:
The problem is not with the tuple, but with your operator. This works fine :
ostream& operator<<(ostream& os_, Mytuple tuple_)
{
os_ << tuple_.get<0>(); // Error because int is implicitly converted into Mytuple. WHYY?
os_ << tuple_.get<1>(); // No Clue Why this is ambiguous.
//os_ << tuple_.get<2>(); // Error because no matching operator. Fine.
return os_;
}
The problem is that the ostringstream inherit operator<< from ostream, which has this signature : ostringstream& operator<<(ostringstream& os_, Mytuple tuple_) is allowed. Then the
ostream& operator<<(ostream& os, T t)
(change T with all available types in c++, see operator<< reference page
EDIT
Here is a simplified example (without a tuple) :
ostringstream& operator<<(ostringstream& os_, Mytuple tuple_)
{
const int i = tuple_.get<0>();
os_ << i; // error in this line
return os_;
}
and the error is now :
dfg.cpp: In function ‘std::ostringstream& operator<<(std::ostringstream&, Mytuple)’:
dfg.cpp:18: error: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
/usr/lib/gcc/i386-redhat-linux/4.3.0/../../../../include/c++/4.3.0/bits/ostream.tcc:111: note: candidate 1: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>]
dfg.cpp:14: note: candidate 2: std::ostringstream& operator<<(std::ostringstream&, Mytuple)
The above error message says : it is not possible to choose between two operators operator<<(ostream&,...) and operator<<(ostringstream&,...). This also raises another question : why on earth do you needoperator<<(ostringstream&,...)`?
When you write
os << tuple_.get<0>();
there is no function that matches both parameters. Instead the compiler has a choice to apply an implicit conversion on either parameter
std::ostream << int
or
std::ostringstream << MyTuple
The latter would happen with the boost::tuple constructor that can take any number of arguments up to number of tuple elements. (And with float it fails, because float is convertible to int.)
When overloading stream operators, use the base class as the left hand side (ostream or even basic_ostream<CharT, Traits>.
Edit: You could disambiguate the call by casting the first argument.
ostringstream& operator<<(ostringstream& os_, Mytuple tuple_)
{
static_cast<std::ostream&>(os_) << tuple_.get<0>();
static_cast<std::ostream&>(os_) << tuple_.get<1>();
static_cast<std::ostream&>(os_) << tuple_.get<2>(); // Error because no matching operator. Fine.
return os_;
}
However, overloading the operator with ostringstream is still a bad idea, because it won't work with operator chaining.
MyTuple a, b;
ostringstream ss;
ss << a << ' ' << b;
will invoke:
1) ostringstream& operator<<(ostringstream& os_, Mytuple tuple_)
2) ostream& ostream::operator<<(char)
3) ostream& operator<<(ostream&&, boost::tuple<int,float,Myclass>
All those people telling you to use ::std::ostream for the type instead of ::std::ostringstream are absolutely correct. You shouldn't be using ::std::ostringstream that way.
But my main beef with your code is the distressing lack of generality. It only works for one particular tuple type, and not all of them.
So I wrote an operator << for ::std::tuple in C++0x that works for any tuple who's members can be individually written using operator <<. It can probably be translated relatively easily to work with Boost's tuple type. Here it is:
template < ::std::size_t fnum, typename tup_type>
void print_fields(::std::ostream &os, const tup_type &val)
{
if (fnum < ::std::tuple_size<tup_type>::value) {
::std::cerr << "Fred " << fnum << '\n';
os << ::std::get<fnum, tup_type>(val);
if (::std::tuple_size<tup_type>::value > (fnum + 1)) {
os << ", ";
}
print_fields<fnum + 1, tup_type>(os, val);
}
}
template < ::std::size_t fnum, typename... Elements>
class field_printer;
template <typename... Elements>
class field_printer<0, Elements...> {
public:
typedef ::std::tuple<Elements...> tup_type;
static void print_field(::std::ostream &os, const tup_type &val) {
}
};
template < ::std::size_t fnum, typename... Elements>
class field_printer {
public:
typedef ::std::tuple<Elements...> tup_type;
static void print_field(::std::ostream &os, const tup_type &val) {
constexpr auto tupsize = ::std::tuple_size<tup_type>::value;
os << ::std::get<tupsize - fnum, Elements...>(val);
if (fnum > 1) {
os << ", ";
}
field_printer<fnum - 1, Elements...>::print_field(os, val);
}
};
template <class... Types>
::std::ostream &operator <<(::std::ostream &os, const ::std::tuple<Types...> &val)
{
typedef ::std::tuple<Types...> tup_type;
os << '(';
field_printer< ::std::tuple_size<tup_type>::value, Types...>::print_field(os, val);
return os << ')';
}
This prints out the tuple as "(element1, element2, ...elementx)".
A (somewhat) outdated article explores ways to use decltype along with SFINAE to detect if a type supports certain operators, such as == or <.
Here's example code to detect if a class supports the < operator:
template <class T>
struct supports_less_than
{
static auto less_than_test(const T* t) -> decltype(*t < *t, char(0))
{ }
static std::array<char, 2> less_than_test(...) { }
static const bool value = (sizeof(less_than_test((T*)0)) == 1);
};
int main()
{
std::cout << std::boolalpha << supports_less_than<std::string>::value << endl;
}
This outputs true, since of course std::string supports the < operator. However, if I try to use it with a class that doesn't support the < operator, I get a compiler error:
error: no match for ‘operator<’ in ‘* t < * t’
So SFINAE is not working here. I tried this on GCC 4.4 and GCC 4.6, and both exhibited the same behavior. So, is it possible to use SFINAE in this manner to detect whether a type supports certain expressions?
In C++11 the shortest most general solution I found was this one:
#include <type_traits>
template<class T, class = decltype(std::declval<T>() < std::declval<T>() )>
std::true_type supports_less_than_test(const T&);
std::false_type supports_less_than_test(...);
template<class T> using supports_less_than = decltype(supports_less_than_test(std::declval<T>()));
#include<iostream>
struct random_type{};
int main(){
std::cout << supports_less_than<double>::value << std::endl; // prints '1'
std::cout << supports_less_than<int>::value << std::endl; // prints '1'
std::cout << supports_less_than<random_type>::value << std::endl; // prints '0'
}
Works with g++ 4.8.1 and clang++ 3.3
A more general solution for arbitrary operators (UPDATE 2014)
There is a more general solution that exploits the fact that all built-in operators are also accessible (and posibly specialized) through STD operator wrappers, such as std::less (binary) or std::negate (unary).
template<class F, class... T, typename = decltype(std::declval<F>()(std::declval<T>()...))>
std::true_type supports_test(const F&, const T&...);
std::false_type supports_test(...);
template<class> struct supports;
template<class F, class... T> struct supports<F(T...)>
: decltype(supports_test(std::declval<F>(), std::declval<T>()...)){};
This can be used in a quite general way, especially in C++14, where type deduction is delayed to the operator wrapper call ("transparent operators").
For binary operators it can be used as:
#include<iostream>
struct random_type{};
int main(){
std::cout << supports<std::less<>(double, double)>::value << std::endl; // '1'
std::cout << supports<std::less<>(int, int)>::value << std::endl; // '1'
std::cout << supports<std::less<>(random_type, random_type)>::value << std::endl; // '0'
}
For unary operators:
#include<iostream>
struct random_type{};
int main(){
std::cout << supports<std::negate<>(double)>::value << std::endl; // '1'
std::cout << supports<std::negate<>(int)>::value << std::endl; // '1'
std::cout << supports<std::negate<>(random_type)>::value << std::endl; // '0'
}
(With the C++11 standard library is a bit more complicated because there is no failure on instatiating decltype(std::less<random_type>()(...)) even if there is no operation defined for random_type, one can implement manually transparent operators in C++11, that are standard in C++14)
The syntax is quite smooth. I hope something like this is adopted in the standard.
Two extensions:
1) It works to detect raw-function applications:
struct random_type{};
random_type fun(random_type x){return x;}
int main(){
std::cout << supports<decltype(&fun)(double)>::value << std::endl; // '0'
std::cout << supports<decltype(&fun)(int)>::value << std::endl; // '0'
std::cout << supports<decltype(&fun)(random_type)>::value << std::endl; // '1'
}
2) It can additionally detect if the result is convertible/comparable to a certain type, in this case double < double is supported but a compile-time false will be returned because the result is not the specified one.
std::cout << supports<std::equal_to<>(std::result_of<std::less<>(double, double)>::type, random_type)>::value << std::endl; // '0'
Note: I just tried to compile the code with C++14 in http://melpon.org/wandbox/ and it didn't work. I think there is a problem with transparent operators (like std::less<>) in that implementation (clang++ 3.5 c++14), since when I implement my own less<> with automatic deduction it works well.
You need to make your less_than_test function a template, since SFINAE stands for Substitution Failure Is Not An Error and there's no template function that can fail selection in your code.
template <class T>
struct supports_less_than
{
template <class U>
static auto less_than_test(const U* u) -> decltype(*u < *u, char(0))
{ }
static std::array<char, 2> less_than_test(...) { }
static const bool value = (sizeof(less_than_test((T*)0)) == 1);
};
int main()
{
std::cout << std::boolalpha << supports_less_than<std::string>::value << endl;
}
This is C++0x, we don't need sizeof-based tricks any more... ;-]
#include <type_traits>
#include <utility>
namespace supports
{
namespace details
{
struct return_t { };
}
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(std::declval<T const&>() < std::declval<T const&>()),
details::return_t
>::value
> { };
}
(This is based on iammilind's answer, but doesn't require that T's operator< return-type be a different size than long long and doesn't require that T be default-constructable.)
Below simple code satisfies your requirement (if you don't want compile error):
namespace supports {
template<typename T> // used if T doesn't have "operator <" associated
const long long operator < (const T&, const T&);
template <class T>
struct less_than {
T t;
static const bool value = (sizeof(t < t) != sizeof(long long));
};
}
Usage:
supports::less_than<std::string>::value ====> true; // ok
supports::less_than<Other>::value ====> false; // ok: no error
[Note: If you want compile error for classes not having operator < than it's very easy to generate with very few lines of code.]
#xDD is indeed correct, though his example is slightly erroneous.
This compiles on ideone:
#include <array>
#include <iostream>
struct Support {}; bool operator<(Support,Support) { return false; }
struct DoesNotSupport{};
template <class T>
struct supports_less_than
{
template <typename U>
static auto less_than_test(const U* u) -> decltype(*u < *u, char(0))
{ }
static std::array<char, 2> less_than_test(...) { }
static const bool value = (sizeof(less_than_test((T*)0)) == 1);
};
int main()
{
std::cout << std::boolalpha << supports_less_than<Support>::value << std::endl;
std::cout << std::boolalpha <<
supports_less_than<DoesNotSupport>::value << std::endl;
}
And results in:
true
false
See it here in action.
The point is that SFINAE only applies to template functions.