Skip to content

Commit 6593448

Browse files
Improve operator resolution
`GetMethodTemplate` now also checks for operators methods using `GetClassOperators` `GetGlobalOperator` can now handle templated types
1 parent 12d2a8e commit 6593448

File tree

2 files changed

+116
-45
lines changed

2 files changed

+116
-45
lines changed

clingwrapper/src/clingwrapper.cxx

Lines changed: 113 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,18 +1484,22 @@ Cppyy::TCppMethod_t Cppyy::GetMethodTemplate(
14841484
std::string pureName;
14851485
std::string explicit_params;
14861486

1487-
if (name.find('<') != std::string::npos) {
1487+
if ((name.find("operator<") != 0) &&
1488+
(name.find('<') != std::string::npos)) {
14881489
pureName = name.substr(0, name.find('<'));
14891490
size_t start = name.find('<');
14901491
size_t end = name.rfind('>');
14911492
explicit_params = name.substr(start + 1, end - start - 1);
1492-
}
1493-
1494-
else pureName = name;
1493+
} else
1494+
pureName = name;
14951495

14961496
std::vector<Cppyy::TCppMethod_t> unresolved_candidate_methods;
14971497
Cpp::GetClassTemplatedMethods(pureName, scope,
14981498
unresolved_candidate_methods);
1499+
if (unresolved_candidate_methods.empty()) {
1500+
// try operators
1501+
Cppyy::GetClassOperators(scope, pureName, unresolved_candidate_methods);
1502+
}
14991503

15001504
// CPyCppyy assumes that we attempt instantiation here
15011505
std::vector<Cpp::TemplateArgInfo> arg_types;
@@ -1520,32 +1524,70 @@ Cppyy::TCppMethod_t Cppyy::GetMethodTemplate(
15201524

15211525
}
15221526

1523-
//
1524-
// static inline
1525-
// std::string type_remap(const std::string& n1, const std::string& n2)
1526-
// {
1527-
// // Operator lookups of (C++ string, Python str) should succeed for the combos of
1528-
// // string/str, wstring/str, string/unicode and wstring/unicode; since C++ does not have a
1529-
// // operator+(std::string, std::wstring), we'll have to look up the same type and rely on
1530-
// // the converters in CPyCppyy/_cppyy.
1531-
// if (n1 == "str" || n1 == "unicode") {
1532-
// if (n2 == "std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >")
1533-
// return n2; // match like for like
1534-
// return "std::string"; // probably best bet
1535-
// } else if (n1 == "float") {
1536-
// return "double"; // debatable, but probably intended
1537-
// } else if (n1 == "complex") {
1538-
// return "std::complex<double>";
1539-
// }
1540-
// return n1;
1541-
// }
1527+
static inline std::string type_remap(const std::string& n1,
1528+
const std::string& n2) {
1529+
// Operator lookups of (C++ string, Python str) should succeed for the
1530+
// combos of string/str, wstring/str, string/unicode and wstring/unicode;
1531+
// since C++ does not have a operator+(std::string, std::wstring), we'll
1532+
// have to look up the same type and rely on the converters in
1533+
// CPyCppyy/_cppyy.
1534+
if (n1 == "str" || n1 == "unicode") {
1535+
// if (n2 ==
1536+
// "std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>
1537+
// >")
1538+
// return n2; // match like for like
1539+
return "std::string"; // probably best bet
1540+
} else if (n1 == "float") {
1541+
return "double"; // debatable, but probably intended
1542+
} else if (n1 == "complex") {
1543+
return "std::complex<double>";
1544+
}
1545+
return n1;
1546+
}
1547+
1548+
void Cppyy::GetClassOperators(Cppyy::TCppScope_t klass,
1549+
const std::string& opname,
1550+
std::vector<TCppScope_t>& operators) {
1551+
if (opname == "operator+")
1552+
Cpp::GetOperator(klass, Cpp::Operator::OP_Plus, operators);
1553+
else if (opname == "operator-")
1554+
Cpp::GetOperator(klass, Cpp::Operator::OP_Minus, operators);
1555+
else if (opname == "operator*")
1556+
Cpp::GetOperator(klass, Cpp::Operator::OP_Star, operators);
1557+
else if (opname == "operator/")
1558+
Cpp::GetOperator(klass, Cpp::Operator::OP_Slash, operators);
1559+
else if (opname == "operator<")
1560+
Cpp::GetOperator(klass, Cpp::Operator::OP_Less, operators);
1561+
else if (opname == "operator<=")
1562+
Cpp::GetOperator(klass, Cpp::Operator::OP_LessEqual, operators);
1563+
else if (opname == "operator>")
1564+
Cpp::GetOperator(klass, Cpp::Operator::OP_Greater, operators);
1565+
else if (opname == "operator>=")
1566+
Cpp::GetOperator(klass, Cpp::Operator::OP_GreaterEqual, operators);
1567+
// FIXME: enabling `==` and `!=` requires friend operators
1568+
// else if (opname == "operator==")
1569+
// Cpp::GetOperator(klass, Cpp::Operator::OP_EqualEqual, operators);
1570+
// else if (opname == "operator!=")
1571+
// Cpp::GetOperator(klass, Cpp::Operator::OP_ExclaimEqual, operators);
1572+
else if (opname == "operator<<")
1573+
Cpp::GetOperator(klass, Cpp::Operator::OP_LessLess, operators);
1574+
else if (opname == "operator>>")
1575+
Cpp::GetOperator(klass, Cpp::Operator::OP_GreaterGreater, operators);
1576+
else if (opname == "operator&")
1577+
Cpp::GetOperator(klass, Cpp::Operator::OP_Amp, operators);
1578+
else if (opname == "operator|")
1579+
Cpp::GetOperator(klass, Cpp::Operator::OP_Pipe, operators);
1580+
}
15421581

15431582
Cppyy::TCppMethod_t Cppyy::GetGlobalOperator(
15441583
TCppType_t scope, const std::string& lc, const std::string& rc, const std::string& opname)
15451584
{
1546-
if ((lc.find('<') != std::string::npos) || (rc.find('<') != std::string::npos)) {
1547-
// arguments of templated types
1548-
return nullptr;
1585+
std::string rc_type = type_remap(rc, lc);
1586+
std::string lc_type = type_remap(lc, rc);
1587+
bool is_templated = false;
1588+
if ((lc_type.find('<') != std::string::npos) ||
1589+
(rc_type.find('<') != std::string::npos)) {
1590+
is_templated = true;
15491591
}
15501592

15511593
std::vector<TCppScope_t> overloads;
@@ -1565,10 +1607,11 @@ Cppyy::TCppMethod_t Cppyy::GetGlobalOperator(
15651607
Cpp::GetOperator(scope, Cpp::Operator::OP_Greater, overloads);
15661608
else if (opname == ">=")
15671609
Cpp::GetOperator(scope, Cpp::Operator::OP_GreaterEqual, overloads);
1568-
else if (opname == "==")
1569-
Cpp::GetOperator(scope, Cpp::Operator::OP_EqualEqual, overloads);
1570-
else if (opname == "!=")
1571-
Cpp::GetOperator(scope, Cpp::Operator::OP_ExclaimEqual, overloads);
1610+
// FIXME: enabling `==` and `!=` requires friend operators
1611+
// else if (opname == "==")
1612+
// Cpp::GetOperator(scope, Cpp::Operator::OP_EqualEqual, overloads);
1613+
// else if (opname == "!=")
1614+
// Cpp::GetOperator(scope, Cpp::Operator::OP_ExclaimEqual, overloads);
15721615
else if (opname == "<<")
15731616
Cpp::GetOperator(scope, Cpp::Operator::OP_LessLess, overloads);
15741617
else if (opname == ">>")
@@ -1578,25 +1621,51 @@ Cppyy::TCppMethod_t Cppyy::GetGlobalOperator(
15781621
else if (opname == "|")
15791622
Cpp::GetOperator(scope, Cpp::Operator::OP_Pipe, overloads);
15801623

1624+
std::vector<Cppyy::TCppMethod_t> unresolved_candidate_methods;
15811625
for (auto overload: overloads) {
1582-
if (Cpp::IsTemplatedFunction(overload))
1583-
continue;
1584-
1585-
TCppType_t lhs_type = Cpp::GetFunctionArgType(overload, 0);
1586-
if (lc != Cpp::GetTypeAsString(Cpp::GetUnderlyingType(lhs_type)))
1626+
if (Cpp::IsTemplatedFunction(overload)) {
1627+
unresolved_candidate_methods.push_back(overload);
15871628
continue;
1588-
1589-
if ((!rc.empty()) && (Cpp::GetFunctionNumArgs(overload) == 2)) {
1590-
TCppType_t rhs_type = Cpp::GetFunctionArgType(overload, 1);
1591-
if (rc != Cpp::GetTypeAsString(Cpp::GetUnderlyingType(rhs_type)))
1592-
continue;
15931629
} else {
1594-
continue;
1595-
}
1630+
TCppType_t lhs_type = Cpp::GetFunctionArgType(overload, 0);
1631+
if (lc_type !=
1632+
Cpp::GetTypeAsString(Cpp::GetUnderlyingType(lhs_type)))
1633+
continue;
15961634

1597-
return overload;
1635+
if (!rc_type.empty()) {
1636+
if (Cpp::GetFunctionNumArgs(overload) != 2)
1637+
continue;
1638+
TCppType_t rhs_type = Cpp::GetFunctionArgType(overload, 1);
1639+
if (rc_type !=
1640+
Cpp::GetTypeAsString(Cpp::GetUnderlyingType(rhs_type)))
1641+
continue;
1642+
}
1643+
return overload;
1644+
}
1645+
}
1646+
if (is_templated) {
1647+
std::string lc_template = lc_type.substr(
1648+
lc_type.find("<") + 1, lc_type.rfind(">") - lc_type.find("<") - 1);
1649+
std::string rc_template = rc_type.substr(
1650+
rc_type.find("<") + 1, rc_type.rfind(">") - rc_type.find("<") - 1);
1651+
1652+
std::vector<Cpp::TemplateArgInfo> arg_types;
1653+
if (auto l = Cppyy::GetType(lc_type, true))
1654+
arg_types.emplace_back(l);
1655+
else
1656+
return nullptr;
1657+
1658+
if (!rc_type.empty()) {
1659+
if (auto r = Cppyy::GetType(rc_type, true))
1660+
arg_types.emplace_back(r);
1661+
else
1662+
return nullptr;
1663+
}
1664+
Cppyy::TCppMethod_t cppmeth = Cpp::BestTemplateFunctionMatch(
1665+
unresolved_candidate_methods, {}, arg_types);
1666+
if (cppmeth)
1667+
return cppmeth;
15981668
}
1599-
16001669
return nullptr;
16011670
}
16021671

clingwrapper/src/cpp_cppyy.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,9 @@ namespace Cppyy {
314314
RPY_EXPORTED
315315
TCppMethod_t GetMethodTemplate(
316316
TCppScope_t scope, const std::string& name, const std::string& proto);
317-
317+
RPY_EXPORTED
318+
void GetClassOperators(Cppyy::TCppScope_t klass, const std::string& opname,
319+
std::vector<TCppScope_t>& operators);
318320
RPY_EXPORTED
319321
TCppMethod_t GetGlobalOperator(
320322
TCppType_t scope, const std::string& lc, const std::string& rc, const std::string& op);

0 commit comments

Comments
 (0)