I am observing a weird behavior, which I cannot explain. The following code (a simplified version of the actual code) compiles correctly in gcc 11.4, and the argument "val" inside the read() method of MyStruct is implicitly converted to a Dummy using the converting constructor.
#include <iostream>
namespace secret_impl_space
{
template <typename T>
struct MyStruct
{
T val;
MyStruct(T v): val(v) {}
// the val below may be implicitly converted to Dummy if operator >> is missing from T
virtual std::istream& read(std::istream& i) { i >> val; return i; }
};
struct Dummy { template<typename T> Dummy(const T& v){}; };
inline std::istream& operator>>(std::istream& i, const Dummy& v)
{
std::cout << "Using Dummy" << std::endl; return i;
}
}
struct A {int a;};
int main()
{
A aa{1};
secret_impl_space::MyStruct<A>* test (new secret_impl_space::MyStruct<A>(aa));
return 0;
}
However, I found that newer gcc versions, starting from 12 on, give me the following compilation error (confirmed with godbolt):
no match for ‘operator>>’ (operand types are ‘std::istream’ {aka ‘std::basic_istream<char>’} and ‘A’)
The weirdest thing is that the code compiles correctly on any gcc version if I do one of the following two things:
- Get rid of the namespace "secret_impl_space"
- Remove the virtual specifier from the read() method.
Can someone explain this behavior? I am honestly puzzled.
Note: just to give the readers some context, in the original code MyStruct was the implementation part of a type-erasing container like boost::any - that is why it has a virtual >> method, to overload the one in the type-erased base interface. The whole idea behind defining the Dummy class was to allow using the type-erased container also for some types that do not have a >> operator - generating a Runtime warning instead of a compiler error. This is pretty terrible IMHO, but I did not write this, it was already around when I found the problem. All this machinery was 'hidden', for some reason (shame?), inside a namespace.
operator>>take its second argument by const reference. Is that intentional?constin reading stream operator? This is part of problem.'operator>>'should be declared prior to the call site or in the global namespace Pretty much explains the problem.