When interfacing with C++ classes and methods it is necessary to re-wrap 
methods as procedures for each derived class. E.g. if I have `Base` and 
`Derived` I would have to repeat wrapping of the `Base` methods for `Derived` 
type. I tried using `method`, but it gives me `'invalid pragma: importcpp: 
"#.toOverride(@)"'` error on the following code:
    
    
    {.emit: """/*TYPESECTION*/
    struct Base {
      int baseField;
      int baseMethod() { return 12; }
      virtual int toOverride() { return 42; }
    
    };
    struct Derived : public Base {
      int derivedField;
      int toOverride() override { return 45; }
    };
    """.}
    
    type
      CxxBase {.importcpp: "Base", bycopy, inheritable.} = object
        baseField: cint
      
      CxxDerived {.importcpp: "Derived", bycopy.} = object of CxxBase
        derivedField: cint
    
    # All methods of the base class must be repeated for each derived. For
    # cases like `QWidget` that has 214 base classes and 37 derived it results
    # in **7918!** repetitions.
    proc baseMethod(base: CxxBase): cint {.importcpp: "#.baseMethod(@)".}
    proc baseMethod(base: CxxDerived): cint {.importcpp: "#.baseMethod(@)".}
    
    proc toOverride(base: CxxBase): cint {.importcpp: "#.toOverride(@)".}
    proc toOverride(base: CxxDerived): cint {.importcpp: "#.toOverride(@)".}
    
    proc toOverrideTypeclass(base: CxxBase | CxxDerived): cint {.importcpp: 
"#.toOverride(@)".}
    
    
    # Ideally I would like to import C++ methods as **methods**, but I get
    # 'Error: invalid pragma: importcpp: "#.toOverride(@)"'
    
    when false:
      method toOverrideMethod(base: CxxBase): cint {.importcpp: 
"#.toOverride(@)".}
    
    block:
      let derived = CxxDerived(baseField: 123123)
      echo derived.baseField
      
      echo CxxBase().toOverride()
      echo CxxDerived().toOverride()
      
      echo CxxBase().toOverrideTypeclass()
      echo CxxDerived().toOverrideTypeclass()
    
    type
      NimBase {.inheritable.} = object
        baseField: cint
      
      NimDerived = object of NimBase
        derivedField: cint
    
    method baseMethod(base: NimBase): int {.base.} = 12
    method toOverride(base: NimBase): int {.base.} = 42
    method toOverride(base: NimDerived): int = 45
    
    block:
      let derived = NimDerived(baseField: 123123)
      echo derived.baseField
      
      echo NimBase().toOverride()
      echo NimDerived().toOverride()
    
    Run

I specifically repeated the implementation in nim as well to illustrate how I 
would like wrapper to behave. It is not difficult to generate additional 
wrappers for all derived classes, but as indicated in comment it could lead to 
multi-thousand repetitions (again `QWidget` has **37** derived classes and it 
would repeat _at least_ **214** methods for each of them. And I used `QWidget` 
as and example. With `QObject` it could be even bigger).

I though about possible solutions, but they don't seem particularly plausible 
to me:

  1. Using typeclasses - `proc toOverride(base: CxxBase | CxxDerived): cint 
{.importcpp: "#.toOverride(@)".}`. It might look fine for such small example, 
but in the end it would mean putting **all** derived class wrappers in a single 
file, and declare all procedures afterwards, creating one giant file from a 
library instead of keeping things separated.
  2. Implementing wrappers as a macro that checks if argument has been derived 
from required base class - this might work, but it seems like a horrible hack 
where I have to mix `{.emit.}` with macro code and traverse full inheritance 
tree on each call encountered in code.


Reply via email to