Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Template functions #199

Closed
nils-werner opened this issue May 19, 2016 · 16 comments
Closed

Template functions #199

nils-werner opened this issue May 19, 2016 · 16 comments

Comments

@nils-werner
Copy link
Contributor

Is it possible to define template functions like

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

namespace py = pybind11;

template <typename T>
T square(T x) {
    return x * x;
}

void pyexport(py::module& m) {
    m.def("square", &square);
}

I always get error messages like

/var/folders/h9/w6465dvd31l5f4bd_j49_4cw0000gp/T/tmpNUt8Ir/ctest.cpp:50:7: error: no matching member function for call to 'def'
    m.def("square", &square);
    ~~^~~
/virtualenv/include/site/python2.7/pybind11/pybind11.h:487:13: note: candidate template ignored: couldn't infer template argument 'Func'
    module &def(const char *name_, Func &&f, const Extra& ... extra) {
            ^
1 error generated.
error: command 'clang' failed with exit status 1

or, when using py::vectorize

/var/folders/h9/w6465dvd31l5f4bd_j49_4cw0000gp/T/tmpc0aYol/ctest.cpp:49:21: error: no matching function for call to 'vectorize'
    m.def("square", py::vectorize(&square));
                    ^~~~~~~~~~~~~
/virtualenv/include/site/python2.7/pybind11/numpy.h:379:66: note: candidate template ignored: couldn't infer template argument 'Return'
detail::vectorize_helper<Return (*) (Args ...), Return, Args...> vectorize(Return (*f) (Args ...)) {
                                                                 ^
/virtualenv/include/site/python2.7/pybind11/numpy.h:383:31: note: candidate template ignored: couldn't infer template argument 'func'
template <typename func> auto vectorize(func &&f) -> decltype(
                              ^
/virtualenv/include/site/python2.7/pybind11/numpy.h:374:49: note: candidate function template not viable: requires 2 arguments, but 1 was provided
detail::vectorize_helper<Func, Return, Args...> vectorize(const Func &f, Return (*) (Args ...)) {
                                                ^
1 error generated.
error: command 'clang' failed with exit status 1
@wjakob
Copy link
Member

wjakob commented May 19, 2016

You can only bind explicitly instantiated versions of your function, e.g. square<int>

@wjakob wjakob closed this as completed May 19, 2016
@nils-werner
Copy link
Contributor Author

Ah, OK! Just for reference, this works:

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

namespace py = pybind11;

template <typename T>
T square(T x) {
    return x * x;
}

void pyexport(py::module& m) {
    m.def("square", square<double>);
    m.def("square", square<float>);
    m.def("square", square<int>);
}

@PaulSt
Copy link

PaulSt commented Aug 22, 2017

Also just for reference, for classes it works like so

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

namespace py = pybind11;

template <typename T>
class C : public SuperClass
{
 C(int foo)	{}
 void func (int baa)
}

template <typename T>
void C<T> :: func(int baa) {}

PYBIND11_MODULE(example, m) {
py::class_< C<double>, shared_ptr< C<double> >, SuperClass>(m, "C")
 .def(py::init<int>())
 .def("func", &C<double>::func);
}

@Pulsar18
Copy link

@PaulSt: what do you need the shared_ptr for in the class binding?

@leimao
Copy link

leimao commented Jan 13, 2020

If I don't use template functions, but still have overloaded functions, for example (for some declarations):

int add(int a, int b);
float add(float a, float b);

Does this mean pybind11 has no solution for this? Even if I want to map the first add to Python function, say, add1, and map the second add to Python function, say, add2?

@leimao
Copy link

leimao commented Jan 13, 2020

Does this mean, if I don't use template functions, but still have overloaded functions, for example (for some declarations):

int add(int a, int b);
float add(float a, float b);

Does this mean pybind11 has no solution for this? Even if I want to map the first add to Python function, say, add1, and map the second add to Python function, say, add2?

Ah, I need to use py::overload_cast with C++ standard 14 for overloaded functions.

@jxramos
Copy link

jxramos commented Jul 28, 2020

How would one bind a template function where the template argument is behind other arguments?

template <typename T>
T square(const char* id, int previous, T x) {
    std::cout << "id = " << id << std::endl;
    return previous* x * x;
}

@bstaletic
Copy link
Collaborator

.def("square_int", square<int>) // For example

@jlucier
Copy link

jlucier commented Nov 17, 2020

For anyone coming across this post confused on how to bind template member functions, I have a solution / questions that would probably be useful to share.

  1. There are situations where it seems to work perfectly to use the "naive" binding shown below. I don't know why, but sometimes the compiler is totally happy with that code and other times it is very unhappy. My C++ naivete is probably showing.
  2. On other occasions, you will get some cryptic errors like error: expected primary-expression before '>' token (referring to the closing > in that line of code). The only remedy I've discovered is to include a pretty sneaky template keyword in the binding definition. Someone more versed in C++ can explain in detail why this makes perfect sense, but this was hard for me to find.
class Foo {
    template<typename T>
    void foo(T t) {
         ...
    }
};

// naive bind that seems to sometimes work and sometimes not work
m.def("foo", &Foo::foo<double>);

// use this to bind (also works for static members), replacing double with whatever specialization
m.def("foo", &Foo::template foo<double>);

Does this make any sense? Any thoughts?

@bstaletic
Copy link
Collaborator

Unless Foo is a template parameter in the second "solution", the template keyword doesn't make sense. If compiler knows what Foo is, then it knows what Foo::foo is. See https://godbolt.org/z/fo85W1 for some simple examples.

@jlucier
Copy link

jlucier commented Nov 18, 2020

@bstaletic That must be it, I've got helper functions that look like the following and that seems to be where you're saying the template keyword is a must.

template<typename T>
auto bind_XX_type(py::class_<T,...>& c) {
     return c.def("bar", &T::bar)
        .def("foo", &T::template foo<double>);
}

bind_XX_type(py::class_<Foo>(m, ...));

@YannickJadoul
Copy link
Collaborator

@jlucier Yep, that must be it. That's probably a "dependent name", then, if I got my terminology correct.

@YannickJadoul
Copy link
Collaborator

(See https://en.cppreference.com/w/cpp/language/dependent_name#The_typename_disambiguator_for_dependent_names)

@atifkarim
Copy link

Also just for reference, for classes it works like so

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

namespace py = pybind11;

template <typename T>
class C : public SuperClass
{
 C(int foo)	{}
 void func (int baa)
}

template <typename T>
void C<T> :: func(int baa) {}

PYBIND11_MODULE(example, m) {
py::class_< C<double>, shared_ptr< C<double> >, SuperClass>(m, "C")
 .def(py::init<int>())
 .def("func", &C<double>::func);
}

@PaulSt Can you please take a look in this example. My goal is to only bind a class template. I will not inherit that one in CPP side. Only a class template will be created in CPP and it will binded. That is my goal.--
somecode.h

#include <string>
#include <iostream>
using namespace std;

template <typename T>
class Sample_World{
    private:
        int x;
    public:
        Sample_World(T val):x(val)
                            {cout<<"Sample_World constructor is called and x: "<<x<<endl;}

        void show_val();

        ~ Sample_World() {};
};

somecode.cpp

#include "somecode.h"
#include <string>
#include <iostream>

template <typename T>
void Sample_World<T>:: show_val(){
    cout<<"from show_val function x: "<<x<<endl;
}

And then I have followed your approch but as I have not so deep idea I am stumbling
binding.cpp

#include <pybind11/pybind11.h>
#include "somecode.h"
namespace py = pybind11;

PYBIND11_MODULE(somecode, m) 
{
py::class_< Sample_World<int>, shared_ptr< Sample_World<int> >>(m, "Sample_World")
 		.def(py::init<int>())
 		.def("show_val", &Sample_World<int>::show_val);
}

Code is compiled successfully but while I have imported the module in py code error is occurred Segmentation fault (core dumped). Please, I badly need help in this regard.

@atifkarim
Copy link

Also just for reference, for classes it works like so

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

namespace py = pybind11;

template <typename T>
class C : public SuperClass
{
 C(int foo)	{}
 void func (int baa)
}

template <typename T>
void C<T> :: func(int baa) {}

PYBIND11_MODULE(example, m) {
py::class_< C<double>, shared_ptr< C<double> >, SuperClass>(m, "C")
 .def(py::init<int>())
 .def("func", &C<double>::func);
}

@PaulSt Can you please take a look in this example. My goal is to only bind a class template. I will not inherit that one in CPP side. Only a class template will be created in CPP and it will binded. That is my goal.--
somecode.h

#include <string>
#include <iostream>
using namespace std;

template <typename T>
class Sample_World{
    private:
        int x;
    public:
        Sample_World(T val):x(val)
                            {cout<<"Sample_World constructor is called and x: "<<x<<endl;}

        void show_val();

        ~ Sample_World() {};
};

somecode.cpp

#include "somecode.h"
#include <string>
#include <iostream>

template <typename T>
void Sample_World<T>:: show_val(){
    cout<<"from show_val function x: "<<x<<endl;
}

And then I have followed your approch but as I have not so deep idea I am stumbling
binding.cpp

#include <pybind11/pybind11.h>
#include "somecode.h"
namespace py = pybind11;

PYBIND11_MODULE(somecode, m) 
{
py::class_< Sample_World<int>, shared_ptr< Sample_World<int> >>(m, "Sample_World")
 		.def(py::init<int>())
 		.def("show_val", &Sample_World<int>::show_val);
}

Code is compiled successfully but while I have imported the module in py code error is occurred Segmentation fault (core dumped). Please, I badly need help in this regard.

Got the solution. The problem was linking class template. But now my question is what is the significance of using Template in Pybind if I statically setup the data type?
My workaround I have given below
sample_temp.h

#ifndef _DO_
#define _DO_

#include <iostream>
using namespace std;

/**
 * A sample class template
 */

template <typename T>
class Sample_World{
    private:
        T x;
    public:
        Sample_World(T val):x(val)
                            {cout<<"Sample_World constructor is called and x: "<<x<<endl;}

        void show_val();

        ~ Sample_World() {};
};

#endif

sample_temp.cpp

#include "sample_temp.h"
#include <iostream>

/**
 * A sample class template function definition
 */

template <typename T>
void Sample_World<T>:: show_val(){
    cout<<"from show_val function x: "<<x<<endl;
}

binding.cpp

#include <pybind11/pybind11.h>
#include "sample_temp.h"
#include "sample_temp.cpp" /*this guy is important*/

namespace py = pybind11;

PYBIND11_MODULE(somecode, m) 
{
py::class_< Sample_World<int>>(m, "Sample_World")
         .def(py::init<int>())
         .def("show_val", &Sample_World<int>::show_val);

}

Idea of using class template header file taken from here

@YannickJadoul
Copy link
Collaborator

@atifkarim, this issue was already closed. It's not the right place or moment to come asking more questions. There's also Gitter to ask questions, rather than adding questions to an old finished thread. (The previous things seemed to be short extra answers, rather than a whole new big question.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants