3

I have been experimenting with C++11 universal references and perfect forwarding in some classes that also need to be accessed from Python using Boost.Python. I have code that works, but it requires some ugly template specialization outside of the class. Has anybody solved this in a more elegant way? Does anybody have any suggestions on improving the following code?

#include <boost/python.hpp>
#include <string>

using namespace boost::python;

struct A {
    A() : _a("initial") {}

    template <typename T>
    void set_a(T&& a) { _a = std::forward<T>(a); }

    const std::string& get_a() const { return _a; }

private:
    std::string _a;
};

// How can the following template member function specialization be avoided?
template <>
void A::set_a(const std::string& a) { _a = a; }

BOOST_PYTHON_MODULE(example)
{
    class_<A>("A")
       .add_property("a", make_function( &A::get_a, return_value_policy<copy_const_reference>()),
                     &A::set_a<const std::string&>) // Can this be defined differently?
    ;
}
jhand
  • 71
  • 5
  • what do you hope to gain from perfect forwarding in this case? save a copy? your specialization effectively completely avoids your forwarding function from being called. – nikolas Jul 29 '13 at 06:09
  • Yes, I am trying to avoid needless construction of temporary objects from the C++ side and avoiding copies. On the C++ side, the equivalent of the set_a() side may be called with Rvalues, Lvalues, and string literals. Performance is very important in those paths. When called from Python, performance is not in any type of performance path, but access to some of the objects is required. The example code probably incorrectly implies that I am trying to avoid a copy from the Python code, but this isn't my intent. – jhand Jul 29 '13 at 13:28

1 Answers1

1

I experimented some today and found the answer is actually pretty simple. Just use make_function() again in the setr part of add_property:

Here is the simplified code:

#include <boost/python.hpp>
#include <string>

using namespace boost::python;

struct A {
    A() : _a("initial") {}

    template <typename T>
    void set_a(T&& a) { _a = std::forward<T>(a); }

    const std::string& get_a() const { return _a; }

private:
    std::string _a;
};

BOOST_PYTHON_MODULE(example)
{
    class_<A>("A")
       .add_property("value",
                     make_function( &A::get_a, return_value_policy<copy_const_reference>()),
                     make_function( &A::set_a<const std::string&> )
    );
}
jhand
  • 71
  • 5