[PYTHON] Type-aware using c ++ templates

Introduction

When I was investigating how to use the C ++ library with a little knowledge of C, templates often came up. At that time, I didn't understand the template well and skipped it, but when I checked it again, it was quite useful, so I summarized the contents I checked with a simple sample and examples that can be used.

environment

template

Template description

When I looked up templates, I was confused by the name template. Forget the meaning of the word template and read it. A template is simply a type-agnostic function (or class). In C ++, it is normal to specify types for variables and return values, but it is useless and impossible to create a function (or class) suitable for all types, so a function (or class) that receives all types with a function called a template ) Can be created.

Template format

Example when applying to arguments

Applying a template is easy. Simply add `template <typename variable name>` above the function (or class), and the type of the specified variable name in that function (or class) will change to the type specified by the caller. To do. You can call it just like a normal function.

cppMain.cpp


template <typename Argument name>
void function name(Argument name){
Processing in the function
}

//How to call
int main(){
    int a = 1;
Function name(a);
Function name<int>(a);
}

Example when applying to the return value

When applying the return type, just add `template <typename variable name>` above the function (or class). What you have to pay attention to here is the type to return with `return```. Since the type returned by return must be the same as the defined return type, the return value name `` in the example below must be returned.

cppMain.cpp


template <typename Return value name>
Return value name Function name(){
Return value name a=value;
Processing in the function
    return a;
}

Simple example of template

In this example, we are creating a function with an argument T that can accept any type. The contents of the function only display the type of the variable T on the standard output. When the int type is given to the function, the std :: string type is given, and the result when the pointer is given is displayed.

cppMain.cpp


#include <typeinfo>
#include <iostream>
#include <cxxabi.h>

template <typename T>
static void print_type(T){
    int status;
    std::cout << "type name:" << abi::__cxa_demangle(typeid(T).name(), 0, 0, &status) << std::endl;
}

int main(){
    int a = 1;
    print_type(a);

    std::string b = "ab";
    print_type(b);

    char* e = "ab";
    print_type(e);
}

result

# ./cppMain
type name:int
type name:std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
type name:char*

Looking at the results, we can see that we can pass all standard types such as ints, classes such as std :: string, and pointers. This time it is a function that only outputs as standard, so I do not know its usefulness, but I will introduce an example that can actually be used in the next example.

Examples of templates that can be used

As an example that can be used in practice, we will take up the converter of Setting the converter between C ++ and python with boostpython. In the previous example, it was a converter limited to int type, but by applying a template, it is now possible to convert other than int type. I also applied a template to the ``` get_list ()` `` function that gets the list so that it returns a different return value even though it is the same function. This makes it unnecessary to create a converter for all types, and if there is a function that can be used in common, it can be handled by simply changing the disclosure port to python.

After application

cppMod.cpp


#include <boost/python.hpp>

#include <iostream>

template <typename T>
struct vec_to_list_convert {
    static PyObject* convert(std::vector<T> const& vec) {
        boost::python::list pyList;
        for (auto item: vec) {
            pyList.append(item);
        }
        return boost::python::incref(pyList.ptr());
    }
};


class Greeting {
    public:

    template <typename T>
    std::vector<T> get_list() {
        std::vector<T> cppVec;
        cppVec.push_back(1);
        cppVec.push_back(2);
        
        return cppVec;
    }
};


BOOST_PYTHON_MODULE(CppMod) {

    boost::python::to_python_converter<const std::vector<int>, vec_to_list_convert<int>>();
    boost::python::to_python_converter<const std::vector<double>, vec_to_list_convert<double>>();

    boost::python::class_<Greeting>("greeting")
    .def("get_int_list", &Greeting::get_list<int>)
    .def("get_double_list", &Greeting::get_list<double>);
}

result

# python3
>>> import CppMod
>>> a=CppMod.greeting()
>>> a.get_int_list()
[1, 2]
>>> a.get_double_list()
[1.0, 2.0]

in conclusion

I have put together a template. Although it is enough knowledge to develop without knowing it, it was very useful for investigating how to use the library and for realizing efficient and clean code-conscious development.

Recommended Posts

Type-aware using c ++ templates
using golang slack editing C2
C code review tool using pycparser
Create a C wrapper using Boost.Python
Execute Python code on C ++ (using Boost.Python)
Export xlsx file in C ++ using libxlsxwriter.
Introduction to Tornado (3): Development using templates [Practice]