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?
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&);
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));
};
}
inline void verify(bool expected, bool actual) {
std::cout << "expected " << expected << ", actual " << actual;
if (expected != actual) std::cout << " (WRONG)";
std::cout << '\n';
}
int main() {
constexpr bool _foo = n::is_ostreamable<foo>::value;
constexpr bool _bar = n::is_ostreamable<bar>::value;
constexpr bool vc = n::is_ostreamable<std::vector<char>>::value;
constexpr bool vi = n::is_ostreamable<std::vector<int>>::value;
constexpr bool vf = n::is_ostreamable<std::vector<foo>>::value;
constexpr bool vb = n::is_ostreamable<std::vector<bar>>::value;
verify(false, _foo);
verify(true , _bar);
verify(false, vc);
verify(true , vi);
verify(false, vf);
verify(true , vb);
}
--
Kyle Markley