Rambles around computer science

Diverting trains of thought, wasting precious time

Sat, 22 Aug 2009

C++ Gotme number 1: operator visibility

I'm doing some C++ coding at the moment. It's a language well-known for “gotchas”, so although it'd be presumptuous for me to assume they'd get you as well, dear reader, I'm going to document some of the things that've caught me out.

namespace dwarf {
	namespace encap {
		typedef Dwarf_Loc expr_instr;
		bool operator==(const expr_instr& e1, const expr_instr& e2);
		bool operator!=(const expr_instr& e1, const expr_instr& e2);
		typedef struct expr
		{
			Dwarf_Half hipc;
			Dwarf_Half lopc;
			std::vector m_expr;
			expr(const Dwarf_Locdesc& desc) : hipc(desc.ld_hipc), lopc(desc.ld_lopc),
				m_expr(desc.ld_s, desc.ld_s + desc.ld_cents) {}
			bool operator==(const expr& e) const 
			{ 
				//expr_instr e1; expr_instr e2; // test
				return hipc == e.hipc &&
					lopc == e.lopc &&
					//e1 == e2; // test
					m_expr == e.m_expr; // error!
			}
			bool operator!=(const expr& e) const { return !(*this == e); }
		} loc_expr;
	}
}

Here we have some code from my C++ binding of libdwarf. I'm trying to use std::vector's builtin == operator to define equality on my struct expr, which is essentially a wrapper for vectors of Dwarf_Loc objects, where Dwarf_Loc is a structure defined by libdwarf. Here's what g++ makes of the above code:

/local/scratch/srk31/opt/bin/../lib/gcc/i686-pc-linux-gnu/4.3.3/../../../../incl
ude/c++/4.3.3/bits/stl_algobase.h: In static member function ?static bool std::_
_equal<_BoolType>::equal(_II1, _II1, _II2) [with _II1 = const Dwarf_Loc*, _II2 =
 const Dwarf_Loc*, bool _BoolType = false]?:
/local/scratch/srk31/opt/bin/../lib/gcc/i686-pc-linux-gnu/4.3.3/../../../../incl
ude/c++/4.3.3/bits/stl_algobase.h:824:   instantiated from ?bool std::__equal_au
x(_II1, _II1, _II2) [with _II1 = const Dwarf_Loc*, _II2 = const Dwarf_Loc*]?
/local/scratch/srk31/opt/bin/../lib/gcc/i686-pc-linux-gnu/4.3.3/../../../../incl
ude/c++/4.3.3/bits/stl_algobase.h:956:   instantiated from ?bool std::equal(_II1
, _II1, _II2) [with _II1 = __gnu_cxx::__normal_iterator > >, _II2 = __gnu_cxx::__normal_itera
tor > >]?
/local/scratch/srk31/opt/bin/../lib/gcc/i686-pc-linux-gnu/4.3.3/../../../../incl
ude/c++/4.3.3/bits/stl_vector.h:1111:   instantiated from ?bool std::operator==(
const std::vector<_Tp, _Alloc>&, const std::vector<_Tp, _Alloc>&) [with _Tp = Dw
arf_Loc, _Alloc = std::allocator]?
dwarfpp.hpp:341:   instantiated from here
/local/scratch/srk31/opt/bin/../lib/gcc/i686-pc-linux-gnu/4.3.3/../../../../incl
ude/c++/4.3.3/bits/stl_algobase.h:795: error: no match for ?operator==? in ?* __
first1 == * __first2?
make: *** [dwarfpp.o] Error 1

Clearly, my definition for operator== isn't being found. But if I uncomment the blamed line and replace it with some dummy code (commented above) which invokes the operator for two dummy objects, rather than vectors, it works fine. Why can I compare two Dwarf_Locs but not two vectors thereof, when vector defines a perfectly good operator== that should just invoke mine?

The answer is that vector's operator== can't see my operator== definition, because of namespaces. According to Stroustrup (C++PL, third edition, section 11.2.4):

Consider a binary operator @. If x is of type X and y is of type Y, x@y is resolved like this:

So the code in std::vector clearly can't see my definitions in dwarf::encap::. However, the reason that this isn't such a common problem is that I'm defining operators on a type, namely Dwarf_Loc, that was defined not by me but in the pre-existing C library that I'm wrapping. I lazily dumped all of libdwarf's definitions into the global namespace, so the quick fix is to define my operator in the global namespace too.

namespace dwarf {
	namespace encap { typedef Dwarf_Loc expr_instr; }
}
bool operator==(const dwarf::encap::expr_instr& e1, const dwarf::encap::expr_instr& e2);
bool operator!=(const dwarf::encap::expr_instr& e1, const dwarf::encap::expr_instr& e2);
namespace dwarf {
	namespace encap {
		//typedef Dwarf_Loc expr_instr;
		typedef struct expr
		{
			Dwarf_Half hipc;
			Dwarf_Half lopc;
			std::vector m_expr;
			expr(const Dwarf_Locdesc& desc) : hipc(desc.ld_hipc), lopc(desc.ld_lopc),
				m_expr(desc.ld_s, desc.ld_s + desc.ld_cents) {}
			bool operator==(const expr& e) const 
			{ 
				//expr_instr e1; expr_instr e2;
				return hipc == e.hipc &&
					lopc == e.lopc &&
					//e1 == e2;
					m_expr == e.m_expr; // okay
			}
			bool operator!=(const expr& e) const { return !(*this == e); }
		} loc_expr;
	}
}

Note that if I'd done the right thing and wrapped libdwarf's definitions into some non-global namespace, say dwarf::lib, I'd still need to do something similar, because my operator definition won't be found if I put it in a different namespace like dwarf::encap, even though that's the namespace containing the code which actually needs the operator to be defined.

Well, it certainly got me... now, on with coding.

[/devel] permanent link contact


Powered by blosxom

validate this page