Uncompile-able results due to namespacing
zwimer opened this issue · 5 comments
TLDR: binder
sees the stream operator <<
in some namespace, B
, then tries to define __str__
using <<
without referencing B
.
Consider:
#include <pybind11/pybind11.h>
#include <ostream>
struct A { int a; };
namespace B {
std::ostream & operator<<(std::ostream & a, const A & b) { return a; }
}
Where a.conf
is just +class A
. We end up with
// File: unknown/unknown.cpp
#include <ios>
#include <locale>
#include <ostream>
#include <sstream> // __str__
#include <streambuf>
#include <string>
#include <functional>
#include <pybind11/pybind11.h>
#include <string>
#include <pybind11/stl.h>
#ifndef BINDER_PYBIND11_TYPE_CASTER
#define BINDER_PYBIND11_TYPE_CASTER
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>)
PYBIND11_DECLARE_HOLDER_TYPE(T, T*)
PYBIND11_MAKE_OPAQUE(std::shared_ptr<void>)
#endif
void bind_unknown_unknown(std::function< pybind11::module &(std::string const &namespace_) > &M)
{
{ // A file: line:8
pybind11::class_<A, std::shared_ptr<A>> cl(M(""), "A", "");
cl.def( pybind11::init( [](){ return new A(); } ) );
cl.def_readwrite("a", &A::a);
cl.def("__str__", [](A const &o) -> std::string { std::ostringstream s; s << o; return s.str(); } );
}
}
If you try to compile this, it will fail because <<
will not be in scope, since the <<
operator was defined in the namespace B
.
Possible solution: Change binder to be explicit with A::operator<<(s, o)
(I like this idea; it is ugly, but this code is autogenerated so that's fine). One other benefit is this would make it clear which <<
operator is being called in the case that multiple are defined at different scopes.
Hi @lyskov,
7b47e78 causes a new issue for me.
If I add the following to test/T07.class.hpp
:
#include <ostream>
namespace operators{
struct Operators
{
friend std::ostream & operator<<(std::ostream & s, const Operators & a) { return s << "Hi"; }
};
}
, test compilation fails:
/home/ghottiger/git/binder/build/test/T07_class.cpp: In lambda function:
/home/ghottiger/git/binder/build/test/T07_class.cpp:104:105: error: ‘operator<<’ is not a member of ‘operators’; did you mean ‘std::operator<<’?
104 | ors::Operators const &o) -> std::string { std::ostringstream s; operators::operator<<(s, o); return s.str(); } );
|
Even though this is perfectly ok C++ code. E.g. run this minimal example:
#include <iostream>
namespace operators {
struct Operators
{
friend std::ostream & operator<<(std::ostream & s, const Operators & a) { return s << a.greetings(); }
std::string greetings() const { return "Hello"; }
};
}
int main() {
operators::Operators s;
std::cout << s << std::endl;
return 0;
}
@hogabrie ah, - i had encounter this or very similar issue before, it became particularly obvious when class and friend function is templated (issue is not specific to operator<<). Solution that i used is to separate declaration of function from it definition. It is a bit verbose but so far this is the only solution that seems to work. Please try following example, it have worked for me:
namespace aaaa {
struct T
{
friend std::ostream & operator<<(std::ostream & s, T const &);
};
inline std::ostream & operator<<(std::ostream & s, T const &) { return s << "hi..."; }
}