Using std::tuple in pyROOT

I tried to create a vector of tuple as follows:

  import ROOT
  a = ROOT.std.vector('tuple<long, long, double, double>')
  b = ROOT.std.make_tuple(1, 2, 3, 4)
  a.push_back(b)

The error message is:

  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  TypeError: none of the 2 overloaded methods succeeded. Full details:
    void std::vector<tuple<long,long,double,double> 
  >::push_back(tuple<long,long,double,double>&& __x) =>
      TypeError: unbound method vector<tuple<long,long,double,double> 
  >::push_back must be called with a vector<tuple<long,long,double,double> > 
  instance as first argument
    void std::vector<tuple<long,long,double,double> >::push_back(const 
  tuple<long,long,double,double>& __x) =>
  TypeError: unbound method vector<tuple<long,long,double,double> >::push_back 
  must be called with a vector<tuple<long,long,double,double> > instance as first argument

Any help are appreciated

ROOT Version: 6.22/02
Platform: ubuntu
Compiler: gcc


Hi @wx2017 ,
There are a couple things to fix in your snippet above.

- a = ROOT.std.vector('tuple<long, long, double, double>')
+ a = ROOT.std.vector('tuple<long, long, double, double>')()

The extra parenthesis are needed to actually declare an instance of the vector, otherwise you are just getting the class. Then you also need to make sure the tuples you create are of the correct type

>>> b = ROOT.std.make_tuple(1, 2, 3, 4)
>>> b
<cppyy.gbl.tuple<int,int,int,int> object at 0x559ae061a9e0>

If you don’t provide the types to the template it will infer them as int (rightfully so). You need to provide them explicitly like

>>> b = ROOT.std.make_tuple[ROOT.long, ROOT.long, ROOT.double, ROOT.double](1, 2, 3, 4)
>>> b
<cppyy.gbl.tuple<long,long,double,double> object at 0x559ae080db30>

With both these things your snippet above will work. Keep in mind that since ROOT 6.22 the new syntax for instantiating templates is with square brackets (as I showed in the example above with b) and you can also pass classes directly instead of strings (e.g. ROOT.long). I find this also helps me with remembering the extra parentheses needed to actually create the class instance.
Cheers,
Vincenzo

1 Like

Thanks. This is very helpful. Here is a follow-up question. I tried to reserve the dimension of a vector and assign the tuple to the vector element,

   import ROOT
   a = ROOT.std.vector('tuple<long, long, double, double>')(2)
   b = ROOT.std.make_tuple[ROOT.long, ROOT.long, ROOT.double, ROOT.double](1, 2, 3, 4)
   a[0] = b

It will produce the following errors:

  Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
 TypeError: tuple<long,long,double,double>& std::vector<tuple<long,long,double,double> 
  >::operator[](unsigned long __n) =>
TypeError: none of the 2 overloaded methods succeeded. Full details:
ROOT::Internal::TEmulatedTuple<long,long,double,double>& 
 tuple<long,long,double,double>::operator= 
(ROOT::Internal::TEmulatedTuple<long,long,double,double>&&) =>
ValueError: could not convert argument 1 (object is not an rvalue)
ROOT::Internal::TEmulatedTuple<long,long,double,double>& 
tuple<long,long,double,double>::operator=(const 
 ROOT::Internal::TEmulatedTuple<long,long,double,double>&) =>
TypeError: could not convert argument 1

Using a.push_back(b) has no issues as you mentioned in the last message.

Thanks

Dear @wx2017 ,
That looks like a bug to me, I have opened an issue at Error when copying a tuple into a specific position of a vector of tuples in PyROOT · Issue #8875 · root-project/root · GitHub .
Cheers,
Vincenzo

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.