root icon indicating copy to clipboard operation
root copied to clipboard

std::function conversion not working with class in nested namespace

Open vepadulano opened this issue 4 months ago • 0 comments

Check duplicate issues.

  • [ ] Checked for duplicates

Description

While trying to use the RNTupleImporter::SetFieldModifier feature, I stumbled upon the following error:

input_line_71:2:19: error: unknown type name 'RFieldBase'
  void fptr_wrap1(RFieldBase& arg0) {
                  ^
Traceback (most recent call last):
  File "/Users/vpadulan/Projects/rootcode/rntuple-importer-set-low-float-precision/repro_setfieldmodifier.py", line 55, in <module>
    raise SystemExit(main())
                     ^^^^^^
  File "/Users/vpadulan/Projects/rootcode/rntuple-importer-set-low-float-precision/repro_setfieldmodifier.py", line 50, in main
    importer.SetFieldModifier(low_precision_modifier)
TypeError: void ROOT::Experimental::RNTupleImporter::SetFieldModifier(ROOT::Experimental::RNTupleImporter::FieldModifier_t modifier) =>
    TypeError: could not convert argument 1

The signature is here with FieldModifier_t being defined within the class here. It looks like the automatic conversion from Python function pointer to std::function is not working in this case, note that RFieldBase should be ROOT::Experimental::RFieldBase but the fully-qualified name is stripped down to the class name only. I am sure it could be simplified, but for now see the attached reproducer which shows the error with RNTupleImporter.

Reproducer

import ROOT
import numpy
import os


class DatasetContext:

    input_file = "input_ttree.root"
    dataset_name = "Events"
    output_file = "output_rntuple.root"

    def __init__(self):
        with ROOT.TFile(self.input_file, "RECREATE") as f:
            main_tree = ROOT.TTree(self.dataset_name, self.dataset_name)
            x = numpy.array([0], dtype=numpy.double)
            y = numpy.array([0], dtype=numpy.double)
            main_tree.Branch("x", x, "x/D")
            main_tree.Branch("y", y, "y/D")

            x[0] = 11.
            y[0] = 22.
            main_tree.Fill()
            x[0] = 33.
            y[0] = 44.
            main_tree.Fill()
            x[0] = 55.
            y[0] = 66.
            main_tree.Fill()

            main_tree.Write()

    def __enter__(self):
        return self

    def __exit__(self, *_):
        os.remove(self.input_file)


def low_precision_modifier(field: ROOT.Experimental.RFieldBase) -> None:
    if field.GetFieldName() == "x":
        field.SetColumnRepresentatives(
            [[ROOT.Experimental.EColumnType.kReal16]])


def main() -> None:
    with DatasetContext() as dataset:
        importer = ROOT.Experimental.RNTupleImporter.Create(
            dataset.input_file, dataset.dataset_name, dataset.output_file)

        importer.SetFieldModifier(low_precision_modifier)
        importer.Import()


if __name__ == "__main__":
    raise SystemExit(main())

ROOT version

Any

Installation method

Any

Operating system

Any

Additional context

No response

vepadulano avatar Oct 07 '24 08:10 vepadulano