@@ -1484,18 +1484,23 @@ 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 );
1493+ } else {
1494+ pureName = name;
14921495 }
14931496
1494- else pureName = name;
1495-
14961497 std::vector<Cppyy::TCppMethod_t> unresolved_candidate_methods;
14971498 Cpp::GetClassTemplatedMethods (pureName, scope,
14981499 unresolved_candidate_methods);
1500+ if (unresolved_candidate_methods.empty ()) {
1501+ // try operators
1502+ Cppyy::GetClassOperators (scope, pureName, unresolved_candidate_methods);
1503+ }
14991504
15001505 // CPyCppyy assumes that we attempt instantiation here
15011506 std::vector<Cpp::TemplateArgInfo> arg_types;
@@ -1520,32 +1525,70 @@ Cppyy::TCppMethod_t Cppyy::GetMethodTemplate(
15201525
15211526}
15221527
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- // }
1528+ static inline std::string type_remap (const std::string& n1,
1529+ const std::string& n2) {
1530+ // Operator lookups of (C++ string, Python str) should succeed for the
1531+ // combos of string/str, wstring/str, string/unicode and wstring/unicode;
1532+ // since C++ does not have a operator+(std::string, std::wstring), we'll
1533+ // have to look up the same type and rely on the converters in
1534+ // CPyCppyy/_cppyy.
1535+ if (n1 == " str" || n1 == " unicode" ) {
1536+ // if (n2 ==
1537+ // "std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>
1538+ // >")
1539+ // return n2; // match like for like
1540+ return " std::string" ; // probably best bet
1541+ } else if (n1 == " float" ) {
1542+ return " double" ; // debatable, but probably intended
1543+ } else if (n1 == " complex" ) {
1544+ return " std::complex<double>" ;
1545+ }
1546+ return n1;
1547+ }
1548+
1549+ void Cppyy::GetClassOperators (Cppyy::TCppScope_t klass,
1550+ const std::string& opname,
1551+ std::vector<TCppScope_t>& operators) {
1552+ if (opname == " operator+" )
1553+ Cpp::GetOperator (klass, Cpp::Operator::OP_Plus, operators);
1554+ else if (opname == " operator-" )
1555+ Cpp::GetOperator (klass, Cpp::Operator::OP_Minus, operators);
1556+ else if (opname == " operator*" )
1557+ Cpp::GetOperator (klass, Cpp::Operator::OP_Star, operators);
1558+ else if (opname == " operator/" )
1559+ Cpp::GetOperator (klass, Cpp::Operator::OP_Slash, operators);
1560+ else if (opname == " operator<" )
1561+ Cpp::GetOperator (klass, Cpp::Operator::OP_Less, operators);
1562+ else if (opname == " operator<=" )
1563+ Cpp::GetOperator (klass, Cpp::Operator::OP_LessEqual, operators);
1564+ else if (opname == " operator>" )
1565+ Cpp::GetOperator (klass, Cpp::Operator::OP_Greater, operators);
1566+ else if (opname == " operator>=" )
1567+ Cpp::GetOperator (klass, Cpp::Operator::OP_GreaterEqual, operators);
1568+ // FIXME: enabling `==` and `!=` requires friend operators
1569+ // else if (opname == "operator==")
1570+ // Cpp::GetOperator(klass, Cpp::Operator::OP_EqualEqual, operators);
1571+ // else if (opname == "operator!=")
1572+ // Cpp::GetOperator(klass, Cpp::Operator::OP_ExclaimEqual, operators);
1573+ else if (opname == " operator<<" )
1574+ Cpp::GetOperator (klass, Cpp::Operator::OP_LessLess, operators);
1575+ else if (opname == " operator>>" )
1576+ Cpp::GetOperator (klass, Cpp::Operator::OP_GreaterGreater, operators);
1577+ else if (opname == " operator&" )
1578+ Cpp::GetOperator (klass, Cpp::Operator::OP_Amp, operators);
1579+ else if (opname == " operator|" )
1580+ Cpp::GetOperator (klass, Cpp::Operator::OP_Pipe, operators);
1581+ }
15421582
15431583Cppyy::TCppMethod_t Cppyy::GetGlobalOperator (
15441584 TCppType_t scope, const std::string& lc, const std::string& rc, const std::string& opname)
15451585{
1546- if ((lc.find (' <' ) != std::string::npos) || (rc.find (' <' ) != std::string::npos)) {
1547- // arguments of templated types
1548- return nullptr ;
1586+ std::string rc_type = type_remap (rc, lc);
1587+ std::string lc_type = type_remap (lc, rc);
1588+ bool is_templated = false ;
1589+ if ((lc_type.find (' <' ) != std::string::npos) ||
1590+ (rc_type.find (' <' ) != std::string::npos)) {
1591+ is_templated = true ;
15491592 }
15501593
15511594 std::vector<TCppScope_t> overloads;
@@ -1565,10 +1608,11 @@ Cppyy::TCppMethod_t Cppyy::GetGlobalOperator(
15651608 Cpp::GetOperator (scope, Cpp::Operator::OP_Greater, overloads);
15661609 else if (opname == " >=" )
15671610 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);
1611+ // FIXME: enabling `==` and `!=` requires friend operators
1612+ // else if (opname == "==")
1613+ // Cpp::GetOperator(scope, Cpp::Operator::OP_EqualEqual, overloads);
1614+ // else if (opname == "!=")
1615+ // Cpp::GetOperator(scope, Cpp::Operator::OP_ExclaimEqual, overloads);
15721616 else if (opname == " <<" )
15731617 Cpp::GetOperator (scope, Cpp::Operator::OP_LessLess, overloads);
15741618 else if (opname == " >>" )
@@ -1578,25 +1622,51 @@ Cppyy::TCppMethod_t Cppyy::GetGlobalOperator(
15781622 else if (opname == " |" )
15791623 Cpp::GetOperator (scope, Cpp::Operator::OP_Pipe, overloads);
15801624
1625+ std::vector<Cppyy::TCppMethod_t> unresolved_candidate_methods;
15811626 for (auto overload: overloads) {
1582- if (Cpp::IsTemplatedFunction (overload))
1627+ if (Cpp::IsTemplatedFunction (overload)) {
1628+ unresolved_candidate_methods.push_back (overload);
15831629 continue ;
1584-
1585- TCppType_t lhs_type = Cpp::GetFunctionArgType (overload, 0 );
1586- if (lc != Cpp::GetTypeAsString (Cpp::GetUnderlyingType (lhs_type)))
1587- 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 ;
15931630 } else {
1594- continue ;
1595- }
1631+ TCppType_t lhs_type = Cpp::GetFunctionArgType (overload, 0 );
1632+ if (lc_type !=
1633+ Cpp::GetTypeAsString (Cpp::GetUnderlyingType (lhs_type)))
1634+ continue ;
15961635
1597- return overload;
1636+ if (!rc_type.empty ()) {
1637+ if (Cpp::GetFunctionNumArgs (overload) != 2 )
1638+ continue ;
1639+ TCppType_t rhs_type = Cpp::GetFunctionArgType (overload, 1 );
1640+ if (rc_type !=
1641+ Cpp::GetTypeAsString (Cpp::GetUnderlyingType (rhs_type)))
1642+ continue ;
1643+ }
1644+ return overload;
1645+ }
1646+ }
1647+ if (is_templated) {
1648+ std::string lc_template = lc_type.substr (
1649+ lc_type.find (" <" ) + 1 , lc_type.rfind (" >" ) - lc_type.find (" <" ) - 1 );
1650+ std::string rc_template = rc_type.substr (
1651+ rc_type.find (" <" ) + 1 , rc_type.rfind (" >" ) - rc_type.find (" <" ) - 1 );
1652+
1653+ std::vector<Cpp::TemplateArgInfo> arg_types;
1654+ if (auto l = Cppyy::GetType (lc_type, true ))
1655+ arg_types.emplace_back (l);
1656+ else
1657+ return nullptr ;
1658+
1659+ if (!rc_type.empty ()) {
1660+ if (auto r = Cppyy::GetType (rc_type, true ))
1661+ arg_types.emplace_back (r);
1662+ else
1663+ return nullptr ;
1664+ }
1665+ Cppyy::TCppMethod_t cppmeth = Cpp::BestOverloadFunctionMatch (
1666+ unresolved_candidate_methods, {}, arg_types);
1667+ if (cppmeth)
1668+ return cppmeth;
15981669 }
1599-
16001670 return nullptr ;
16011671}
16021672
0 commit comments