Reputation: 46
I'm in the middle of writing an AST for a toy compiler (subset of C++), and I've encountered this particular error:
type.hpp:
namespace evc
{
namespace ast
{
enum class type_t;
struct type : public ast
{
using ast::ast;
type_t m_type;
type* m_subtype; // for const, array, references, pointers, etc.
// Checks if two types are the the same or not
friend bool operator==(const evc::ast::type& lhs, const evc::ast::type& rhs);
};
}
}
type.cpp:
#include <ast/type.hpp>
bool operator==(const evc::ast::type& lhs, const evc::ast::type& rhs)
{
if (lhs.m_type == rhs.m_type)
{
if (lhs.m_subtype != nullptr && rhs.m_subtype != nullptr)
{
return (*lhs.m_subtype == *rhs.m_subtype);
}
else
{
return (lhs.m_subtype == nullptr && rhs.m_subtype == nullptr);
}
}
else
{
return false;
}
}
Error:
g++ -Wall -Wextra -Wc++11-compat -pedantic -Werror -std=c++14 -I inc
src/ast/type.cpp: In function 'bool operator==(const evc::ast::type&, const evc::ast::type&)':
src/ast/type.cpp:52:36: error: ambiguous overload for 'operator==' (operand types are 'evc::ast::type' and 'evc::ast::type')
return (*lhs.m_subtype == *rhs.m_subtype);
^
src/ast/type.cpp:52:36: note: candidates are:
src/ast/type.cpp:46:6: note: bool operator==(const evc::ast::type&, const evc::ast::type&)
bool operator==(const evc::ast::type& lhs, const evc::ast::type& rhs)
^
In file included from src/ast/type.cpp:1:0:
inc/ast/type.hpp:37:25: note: bool evc::ast::operator==(const evc::ast::type&, const evc::ast::type&)
friend bool operator==(const evc::ast::type& lhs, const evc::ast::type& rhs);
I understand what ambiguity is (when writing a compiler, you'd hope I would!), but I don't understand why it is ambiguous. It looks to me like the compiler is dropping the const reference part and then saying it is invalid. This is really puzzling, and I've been banging my head over it since yesterday morning. Just wondering if I can grab a hand?
I am also aware that the design of this node could be improved. Already have a better class planned out, but this problem will still be an issue. Baby steps.
Cheers :)
Upvotes: 0
Views: 2661
Reputation: 554
In the header, the friend function is declared inside the namespace, whereas the definition in the source is in the global namespace. Solution is to move the friend function out of the namespace in the header:
// Predeclaration
namespace evc { namespace ast { struct type; } }
// Declare the friend function in the global namespace
bool operator==(const evc::ast::type& lhs, const evc::ast::type& rhs);
namespace evc
{
namespace ast
{
enum class type_t;
struct type : public ast
{
using ast::ast;
type_t m_type;
type* m_subtype; // for const, array, references, pointers, etc.
// Explicitly state the operator is declared in the global namespace
friend bool ::operator==(const evc::ast::type& lhs, const evc::ast::type& rhs);
};
}
}
or (as James suggests) move the definition inside the namespace by defining it as:
bool evc::ast::operator==(const evc::ast::type& lhs, const evc::ast::type& rhs)
{
...
}
Either solution will resolve the ambiguity.
Upvotes: 1
Reputation: 153909
You've two operator==
, one in namespace evc::ast
, and the
other in global namepace. Your definition is in the global
namespace, and so finds the one in the global namespace, but ADL
also finds the one in evc::ast
, so the expression is
ambiguous. (Which is exactly what the error messages say. They list the functions being considered.)
Upvotes: 3