Efficient mechanism to generate operator overload functions
I was looking a bit at your PyCXX and want to offer you Barton–Nackman trick using Curiously recurring template pattern together with variadic template recursion (through partial specialization). This way you can solve all your types and conversion operators with one template:

template&lt;typename T&gt; struct Arithmetic;
using Long = Arithmetic&lt;long long&gt;;
using Double = Arithmetic&lt;long double&gt;;

template&lt;class Base, class... Other&gt; struct compare_operators {};

template&lt;class Base, class First, class... Other&gt;
  struct compare_operators&lt;Base, First, Other...&gt;
  : compare_operators&lt;Base, Other...&gt;
{
    friend bool operator == (const Base&amp; a, First b) {
        return a.template as&lt;First&gt;() == b; }
    friend bool operator != (const Base&amp; a, First b) {
        return a.template as&lt;First&gt;() != b; }
    friend bool operator &lt;  (const Base&amp; a, First b) {
        return a.template as&lt;First&gt;() &lt;  b; }
    friend bool operator &lt;= (const Base&amp; a, First b) {
        return a.template as&lt;First&gt;() &lt;= b; }
    friend bool operator &gt;  (const Base&amp; a, First b) {
        return a.template as&lt;First&gt;() &gt;  b; }
    friend bool operator &gt;= (const Base&amp; a, First b) {
        return a.template as&lt;First&gt;() &gt;= b; }

    friend bool operator == (const Base&amp; a, const Arithmetic&lt;First&gt;&amp; b) {
        return a.template as&lt;First&gt;() == b.value; }
    friend bool operator != (const Base&amp; a, const Arithmetic&lt;First&gt;&amp; b) {
        return a.template as&lt;First&gt;() != b.value; }
    friend bool operator &lt;  (const Base&amp; a, const Arithmetic&lt;First&gt;&amp; b) {
        return a.template as&lt;First&gt;() &lt;  b.value; }
    friend bool operator &lt;= (const Base&amp; a, const Arithmetic&lt;First&gt;&amp; b) {
        return a.template as&lt;First&gt;() &lt;= b.value; }
    friend bool operator &gt;  (const Base&amp; a, const Arithmetic&lt;First&gt;&amp; b) {
        return a.template as&lt;First&gt;() &gt;  b.value; }
    friend bool operator &gt;= (const Base&amp; a, const Arithmetic&lt;First&gt;&amp; b) {
        return a.template as&lt;First&gt;() &gt;= b.value; }
};

template&lt;typename T&gt; struct Arithmetic
  : compare_operators&lt;Arithmetic&lt;T&gt;
  , long long, int, short, double, float, long double&gt;
{
    T value;
    Arithmetic(T value): value(value) {}

    template&lt;typename X, typename = enable_if_t&lt;is_arithmetic&lt;decay_t&lt;X&gt;&gt;::value&gt;&gt;
      X as() const { return (X)value; }
};

int main() {
    Long val(3);
    if(val &gt; 2) cout &lt;&lt; "val &gt; 2\n";
    if(val &lt;= 3.2) cout &lt;&lt; "val &lt;= 3.2\n";
    Double dbl(3.14);
    if(val &lt; dbl) cout &lt;&lt; "val &lt; dbl\n";
}


Beware that the comparision operators need some fine-tuning especially when you compare integral vs. floating-point (which to choose as common type) and that dacay_t in conversion operator may be problematic (not sure). (Finally imagine using namespace std, but I use my own header while explicitly using selected std features/classes in the namespace and then using the namespace).



BTW: This would be the same (but the as conversion is altered) in my own syntax, which you may find a bit familiar:

#include "basics.hpp"
using*firda

forward template&lt;typename T&gt; struct Arithmetic
using Long = Arithmetic&lt;long long&gt;
using Double = Arithmetic&lt;long double&gt;

template&lt;class Base, class... Other&gt;
  struct compare_operators

template&lt;class Base, class First, class... Other&gt;
  struct compare_operators&lt;Base, First, Other...&gt;
  : compare_operators&lt;Base, Other...&gt;

    friend bool operator == (const Base&amp; a, First b)
        return a.template as&lt;First&gt;() == b
    friend bool operator != (const Base&amp; a, First b)
        return a.template as&lt;First&gt;() != b
    friend bool operator &lt;  (const Base&amp; a, First b)
        return a.template as&lt;First&gt;() &lt;  b
    friend bool operator &lt;= (const Base&amp; a, First b)
        return a.template as&lt;First&gt;() &lt;= b
    friend bool operator &gt;  (const Base&amp; a, First b)
        return a.template as&lt;First&gt;() &gt;  b
    friend bool operator &gt;= (const Base&amp; a, First b)
        return a.template as&lt;First&gt;() &gt;= b

    friend bool operator == (const Base&amp; a, const Arithmetic&lt;First&gt;&amp; b)
        return a.template as&lt;First&gt;() == b.value
    friend bool operator != (const Base&amp; a, const Arithmetic&lt;First&gt;&amp; b)
        return a.template as&lt;First&gt;() != b.value
    friend bool operator &lt;  (const Base&amp; a, const Arithmetic&lt;First&gt;&amp; b)
        return a.template as&lt;First&gt;() &lt;  b.value
    friend bool operator &lt;= (const Base&amp; a, const Arithmetic&lt;First&gt;&amp; b)
        return a.template as&lt;First&gt;() &lt;= b.value
    friend bool operator &gt;  (const Base&amp; a, const Arithmetic&lt;First&gt;&amp; b)
        return a.template as&lt;First&gt;() &gt;  b.value
    friend bool operator &gt;= (const Base&amp; a, const Arithmetic&lt;First&gt;&amp; b)
        return a.template as&lt;First&gt;() &gt;= b.value

template&lt;typename T&gt; struct Arithmetic
  : compare_operators&lt;Arithmetic&lt;T&gt;
  , long long, int, short, double, float, long double&gt;

    T value
    Arithmetic(T value): value(value) {}

    template&lt;typename X&gt;
      enable_if_t&lt;is_arithmetic&lt;X&gt;::value,
      X&gt; as() const
        return value

int main()
    Long val(3)
    if val &gt; 2; cout &lt;&lt; "val &gt; 2\n"
    if val &lt;= 3.2; cout &lt;&lt; "val &lt;= 3.2\n"
    Double dbl(3.14)
    if val &lt; dbl; cout &lt;&lt; "val &lt; dbl\n"