binder icon indicating copy to clipboard operation
binder copied to clipboard

problem in std vector of pointer as argument

Open yosoufe opened this issue 6 years ago • 8 comments

Hi. In binding of something like the following

Class B { // Virtual Base class
    virtual void f()=0;
}
Class A
{
    ....
    void someFunction(const char* s, std::vector<B*> bs) {....}
}

I get the following binding code:

cl.def("someFunction", (void (A::*)(const char *, int)) &A::someFunction);

Do you know why the std::vector<B*> is turned to int in the second argument of someFunction??

Of course I cannot compile the binding codes.

yosoufe avatar Apr 24 '19 00:04 yosoufe

I cannot replicate it anymore but I do not know why the binding code for that someFunction is not generated.

yosoufe avatar Apr 24 '19 18:04 yosoufe

hm... i can not replicate this locally (see code that i used below) - bindings seems to be generated for someFunction for that example and have corrected argument types. Could it be that your production code pickup overload for someFunction that used int as an argument?

struct B { // Virtual Base class
    virtual void f()=0;
};
struct A {
    void someFunction(const char* s, std::vector<B*> bs) {}
};

P.S: for future bug reports could you please post actual code that that is compellable? Thanks,

lyskov avatar Apr 24 '19 19:04 lyskov

Thanks. Can you share what do I need to bind your example? I guess I am missing something

yosoufe avatar Apr 24 '19 20:04 yosoufe

I think the easiest way to create bindings for isolated piece of code would be replicate steps in Binder testing script (see https://github.com/RosettaCommons/binder/blob/master/test/self-test.py) or just add custom test into https://github.com/RosettaCommons/binder/tree/master/test and re-run the test suite with your new test file as an argument.

lyskov avatar Apr 24 '19 20:04 lyskov

This is expected: C++ class types have by default they members declared as private (while struct have them by default as public), so to replicate this with classes you will need to explicitly add public labels, like this:

class B {
public:
    virtual void f()=0;
};
class A
{
public:
    void someFunction(const char* s, std::vector<B*> bs) {}
};

On Apr 24, 2019, at 15:40, Yousof [email protected] wrote:

It seems that the above example works as struct but not as class. Could you try that?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/RosettaCommons/binder/issues/71#issuecomment-486437823, or mute the thread https://github.com/notifications/unsubscribe-auth/AAZGKUCU6KR3U3UZKBMMUKLPSDHURANCNFSM4HH7L4LQ.

lyskov avatar Apr 24 '19 21:04 lyskov

Sorry. I noticed that and deleted my previous message.

I have a problem regarding this. As I said before I am writing a C++ API and make python bindings for it. My Public header file is like this:

// file: "api.h"
#pragma once

#include <stdint.h>
#include <cstddef>
#include <string>
#include <vector>

namespace ApiNameSpace
{
  struct Base0
  {
    virtual ~Base0();
    virtual Base0* copy() const = 0;
  };
  struct Base1 : public Base0
  {
    enum enumType
    {
      t1,  t2,  t3, t4
    };
    double v;
    enumType   e;
  };
  class builder
  {
  public:
    builder();
    int nonVectorFunction (const char* ch, int a);
    int someFunction1(const char* ch, std::vector<Base1*> bs);
  };
}

And I am making binding code for this file and link it with the required libraries when compiling the binding codes. You can try to make binding for the above file.

In this case, the binder does not make someFunction1 code for me. If I change the definition to int someFunction1(const char* ch, std::vector<Base1*> bs) {}; (with curly brackets at the end - empty implementation) It does generate the binding.

Note that nonVectorFunction is always being generated.

Do you have any Idea how can I overcome this issue??

With empty {}, the bind_std_stl_vector is generated, but without {}, it does not. How can I force the generation of bind_std_stl_vector??

Thanks

yosoufe avatar Apr 25 '19 00:04 yosoufe

I made some progress. If I change to the following I get the binding code

// file: "api.h"
#pragma once

#include <stdint.h>
#include <cstddef>
#include <string>
#include <vector>

namespace ApiNameSpace
{
  struct Base0
  {
    virtual ~Base0();
    virtual Base0* copy() const = 0;
  };
  struct Base1 : public Base0
  {
    enum enumType
    {
      t1,  t2,  t3, t4
    };
    double v;
    enumType   e;
  };
}; // end of namespace

// add the instantiation of the vector
template class std::vector<ApiNameSpace::Base1*>;

namespace ApiNameSpace{
  class builder
  {
  public:
    builder();
    int nonVectorFunction (const char* ch, int a);
    int someFunction1(const char* ch, std::vector<Base1*> bs);
  };
};

But when I compile with the pybind11 (not the one coming with binder from build.py) I get the following error

error: static assertion failed: Holder classes are only supported for custom types
     static_assert(std::is_base_of<base, type_caster<type>>::value,

Any hints?

yosoufe avatar Apr 25 '19 00:04 yosoufe

RE absence of bindings for someFunction1: this is expected behavior: Binder can only bind functions that have fully defined argument types. So for case of template arguments this mean that there have to be point of instantiation. And adding line like template class std::vector<ApiNameSpace::Base1*>; (as you did above) is one way to trigger template instantiation.

RE compiling with different version of Pybind11: upgrading to use newer version of Pybind11 usually take considerable efforts so that's why i provide separate version of Pybind11 that known to be compatible with current version of Binder. From your log it looks like upgraded version of Pybind11 broke something, my guess is that template code for handling custom return policy might need to be updated but it is only a guess so i can not say anything definitive without investigating this further.

lyskov avatar Apr 25 '19 19:04 lyskov