Unexpected SFINAE behavior

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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





[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux