On 23 June 2013 19:12, Kyle Markley wrote: > Hello, > > I am looking for some help with some unexpected SFINAE behavior. I am using > gcc 4.8.1. I wrote a trait to detect if a type can be sent to a > std::ostream through operator<<, but I have observed it to fail when: > > 1) The trait is declared in a namespace > 2) The same namespace contains an operator<< declaration > > Then, the trait fails when I evaluate it for a type *unrelated* to the > operator<< in the namespace. If move the trait or the operator<< > declaration outside the namespace, it works. It also works if I remove that > operator<< declaration. > > In my specific case I am declaring an operator<< for std::vector<int>, so I > expect the trait to be 'true'. But when I declare operator<< for the > unrelated type 'baz' inside the same namespace as the trait, then the > std::vector<int> evaluation becomes 'false'. The other types I am > experimenting with are curiously not affected. > > What am I dong wrong? This is nothing to do with SFINAE, if you actually try writing a std::vector<int> to an ostream in that namespace (see below) you'll find it won't compile, so the is_ostreamable trait is correct. In the namespace name-lookup finds the operator<< overload for baz and doesn't look in any enclosing scopes. ADL doesn't find the right operator because it isn't in an associated namespace. > g++ -std=c++11 -Wall -Wextra -fPIC report.cpp -o report > > report.cpp > ======= > #include <cstddef> > #include <utility> > #include <vector> > #include <iostream> > > struct foo { }; > struct bar { }; > struct baz { }; > > std::ostream& operator<<(std::ostream&, const bar&); > std::ostream& operator<<(std::ostream&, const std::vector<int>&); > std::ostream& operator<<(std::ostream&, const std::vector<bar>&); > > namespace n { > > // > // Declaring this function in this namespace causes the variable 'vi' > // below in main() to become false. > // > // There is no problem if this function is not declared, or declared > // outside the namespace. > // > std::ostream& operator<<(std::ostream&, const baz&); > void test() { std::vector<int> v; std::cout << v; // fails } > template <typename T> > struct is_ostreamable > { > struct n { char data[1]; }; > struct y { char data[2]; }; > template <typename U> > static n check(...); > template <typename U, typename = > decltype(std::declval<std::ostream&>() << std::declval<const U&>())> > static y check(std::nullptr_t); > static constexpr bool value = sizeof(y) == sizeof(check<T>(nullptr)); > }; N.B. You can use std::true_type and std::false_type to simplify this sort of trait in C++11.