Cython:使用嵌套的typedef公开C ++类 [英] Cython : exposing C++ classes with nested typedef (s)

查看:143
本文介绍了Cython:使用嵌套的typedef公开C ++类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据这个问题/答案,无法在cython中直接重写C ++嵌套的typedef.我有这样的问题,我不知道哪种是正确的/最佳的进行方式.

According to this question/answer in stackoverflow, it is not possible to directly rewrite C++ nested typedefs in cython. I have such a problem and I don't know which is the right/optimal way to proceed.

让我更具体地举例说明.在下面,您可以找到两个C ++文件(一个header.h和一个.cpp)以及两个相应的cython文件(一个.pxd和一个.pyx)的内容.在名为cpp_graph.h的C ++头文件中,您可以看到嵌套的typedef声明.例如,对应于Graph::iterator::nn_iterator的那个. 我不知道如何在相应的graph.pxd文件中公开它.换句话说,我不知道执行此操作的正式"或标准"方式是什么.

Let me be more specific with an example. Below, you can find the content of two C++ files (one header.h and one .cpp) and of two corresponding cython files (one .pxd and one .pyx). In the C++ header file called cpp_graph.h you can see nested typedef declarations; for example, that corresponding to Graph::iterator::nn_iterator. I don't know how to expose that in the corresponding graph.pxd file. Or, in other words, I don't know what is the "official" or "standard" way to do it.

一些相关信息.如果检查cython包装器的STL,则可以找到嵌套的typedef.例如,utility.pxd中的此处vector.pxd文件中的此处 .但是,这些ctypedef的嵌套用法仅用于模板声明. 是不是仅在cython中嵌套typedef才可用于模板声明?

Some relevant information. If you check the cython wrapper for STL you can find nested typedefs. For example here in the utility.pxd or here in the vector.pxd file. However, those nested usages of ctypedef are used for template declarations only. Is it the case that nested typedefs work for template declarations only in cython?

C ++头文件:

// file : cpp_graph.h

#ifndef Included_cpp_graph
#define Included_cpp_graph

#include <cassert>
#include <cstddef>
#include <set>
#include <map>
#include <iostream>
#include <string>
#include <sstream>
#include "to_string_patch.h"

#ifndef Defined_bint
#define Defined_bint
typedef int                                          bint;
#endif

class Graph {
    public:
        typedef std::set< int >                      t_nn;
        typedef std::set< int >::iterator            nn_iterator;
        typedef std::map< int , t_nn >               t_node_to_nn;    
        class iterator
        {
            // To iterate over nodes.
            friend class Graph;
            public:
                typedef iterator self_type;
                typedef int value_type;
                typedef int & reference;
                typedef int * pointer;                
                typedef t_node_to_nn::iterator map_iterator; 
                typedef std::forward_iterator_tag iterator_category;
                iterator( map_iterator map_it ) : _map_it( map_it ) { }
                self_type operator++()         { _map_it++; return *this;                  } // PREFIX
                self_type operator++(int junk) { self_type i = *this; _map_it++; return i; } // POSTFIX  
                value_type    operator*()  { return   ( * _map_it ).first;  } // Return the index "i"
                Graph::t_nn * operator->() { return & ( * _map_it ).second; } // Return a pointer to the contained t_nn.
                bool operator==( const self_type & rhs ) { return _map_it == rhs._map_it; }
                bool operator!=( const self_type & rhs ) { return _map_it != rhs._map_it; }
            private:
                map_iterator _map_it;
        };    
        class const_iterator
        {
            friend class Vertex;        
            public:
                typedef const_iterator self_type;
                typedef int value_type;
                typedef int & reference;
                typedef int * pointer;                
                typedef t_node_to_nn::iterator map_iterator;
                typedef std::forward_iterator_tag iterator_category;
                const_iterator( map_iterator map_it ) : _map_it( map_it ) { }
                self_type operator++()         { _map_it++; return *this;                  } // PREFIX
                self_type operator++(int junk) { self_type i = *this; _map_it++; return i; } // POSTFIX 
                const value_type    operator*()  { return   ( * _map_it ).first;  } // Return the index "i"
                const Graph::t_nn * operator->() { return & ( * _map_it ).second; } // Return a pointer to the contained t_nn.
                bool operator==( const self_type& rhs ) { return _map_it == rhs._map_it; }
                bool operator!=( const self_type& rhs ) { return _map_it != rhs._map_it; }
            private:
                map_iterator _map_it;
        };     
        iterator begin() { _node_to_nn.begin(); }
        iterator end()   { _node_to_nn.end();   }        
        const_iterator begin() const { _node_to_nn.begin(); }
        const_iterator end()   const { _node_to_nn.end();   }        
        nn_iterator nn_begin( int i ) { assert( has_node( i ) ); return _node_to_nn[ i ].begin(); }
        nn_iterator nn_end( int i )   { assert( has_node( i ) ); return _node_to_nn[ i ].end();   }
        Graph() : _num_links( 0 ) {}
        ~Graph() { _node_to_nn.clear(); _num_links = 0; }
        Graph & subgraph( std::set< int > & nodes ) {
            Graph * S = new Graph();
            for ( std::set< int >::iterator n_it = nodes.begin() ; n_it != nodes.end() ; n_it++ ) {
                int i = ( * n_it );
                assert( has_node( i ) );
                for ( nn_iterator j_it = nn_begin( i ) ; j_it != nn_end( i ) ; j_it++ ) { 
                    int j = ( * j_it );
                    if ( nodes.count( j ) > 0 ) { S -> add_link( i , j ); }
                }
            }
            return ( * S );
        }
        int num_nodes() { return _node_to_nn.size(); }
        int num_links() { return _num_links; }
        int degree( int i )  { return _node_to_nn[ i ].size(); }
        double avrg_degree() { return ( ( double ) 2 * num_nodes() ) / ( ( double ) _num_links ); }
        bool has_node( int i ) { return _node_to_nn.count( i ) > 0; }
        bool has_nn( int i , int j ) { 
            if ( has_node( i ) ) { return _node_to_nn[ i ].count( j ) > 0; }
            return false;
        }
        bool has_link( int i , int j ) { return has_nn( i , j ); }
        void add_node( int i ) { _node_to_nn[ i ].count( 0 ); } // Trick...
        void add_link( int i , int j ) { 
            if ( has_link( i , j ) ) { return; }
            _node_to_nn[ i ].insert( j );
            _node_to_nn[ j ].insert( i );
            _num_links += 1;
        }
        void del_link( int i , int j ) {
            if ( has_link( i , j ) ) { 
                _node_to_nn[ i ].erase( j );
                _node_to_nn[ j ].erase( i );
                _num_links -= 1;
            }
        }
        void del_node( int i ) { 
            iterator i_it = _node_to_nn.find( i ); 
            for( nn_iterator j_it = i_it -> begin() ; j_it != i_it -> end() ; j_it++ ) { del_link( i , ( * j_it ) ); }
            _node_to_nn.erase( i_it._map_it );
        }
        void clear_node( int i ) { del_node( i ); add_node( i ); } // Trick...
    private:
        t_node_to_nn    _node_to_nn;
        int             _num_links;
};

std::ostream& operator<<( std::ostream& os , Graph & G );

typedef Graph::t_nn Graph_t_nn
typedef 

#endif // Included_cpp_graph

C ++ .cpp文件:

The C++ .cpp file:

// cpp_graph.cpp

#include <cassert>
#include <cstddef>
#include <set>
#include <map>
#include <iostream>
#include <string>
#include <sstream>
#include "to_string_patch.h"
#include "cpp_graph.h"

std::ostream& operator<<( std::ostream& os , Graph & G ) {    
    os << "Graph{";
    // Print nodes.
    for ( Graph::iterator i_it = G.begin() ; i_it != G.end() ; i_it++ ) {
        int i = ( * i_it );
        os << " " << patch::to_string( i );
    }
    os << " |";
    // Print edges.              
    for ( Graph::iterator i_it = G.begin() ; i_it != G.end() ; i_it++ ) {
        int i = ( * i_it );
        for ( Graph::nn_iterator j_it = G.nn_begin( i ) ; j_it != G.nn_end( i ) ; j_it++ ) {
            int j = ( * j_it );
            if ( i < j ) { os << " " + patch::to_string( i ) << ":" << patch::to_string( j ); }
        }
    }
    os << " }"; // << std::endl;
    return os;
}   

// === For testing purposes ===.
/*
int main() {

    Graph G;   
    G.add_link( 1 , 2 );
    G.add_link( 1 , 3 );
    G.add_link( 2 , 3 );
    G.add_link( 3 , 4 );
    G.add_link( 4 , 5 );                
    G.add_link( 4 , 6 );
    G.add_link( 5 , 6 );            
    std::cout << G << std::endl;

    G.del_link( 3 , 4 );
    std::cout << G << std::endl;    

    G.del_node( 3 );
    std::cout << G << std::endl;    

    G.clear_node( 2 );
    std::cout << G << std::endl;    

    G.add_link( 100 , 101 );
    std::cout << G << std::endl;    
    std::cout << "N = " << G.num_nodes() << " M = " << G.num_links() << std::endl;        

}
*/

cython .pxd文件:

The cython .pxd file:

# file : graph.pxd

# === Cython cimports ===

from libcpp cimport bool
from libcpp.set cimport set as cset
from libcpp.map cimport map as cmap
from cython.operator cimport dereference as deref, preincrement as inc

# === Exposing the C++ Graph class ===

cdef extern from "cpp_graph.h":
    cdef cppclass Graph:
        #public:
        ctypedef cset[ int ]                     t_nn
        ctypedef cset[ int ].iterator            nn_iterator
        ctypedef cmap[ int , t_nn ]              t_node_to_nn
        cppclass iterator:
            #friend class Graph;
            #public:
            typedef iterator self_type
            typedef int value_type
            typedef int & reference
            typedef int * pointer
            typedef t_node_to_nn::iterator map_iterator
            typedef std::forward_iterator_tag iterator_category
            iterator( map_iterator map_it )
            self_type operator++()
            self_type operator++(int junk)
            value_type    operator*()
            Graph::t_nn * operator->()
            bool operator==( const self_type & rhs )
            bool operator!=( const self_type & rhs )
            #private:
            #    map_iterator _map_it;
        cppclass const_iterator:
            #friend class Vertex;        
            #public:
            typedef const_iterator self_type
            typedef int value_type
            typedef int & reference
            typedef int * pointer               
            typedef t_node_to_nn::iterator map_iterator
            typedef std::forward_iterator_tag iterator_category
            const_iterator( map_iterator map_it )
            self_type operator++()
            self_type operator++(int junk)
            const value_type    operator*()
            const Graph::t_nn * operator->()
            bool operator==( const self_type& rhs )
            bool operator!=( const self_type& rhs )
            #private:
            #    map_iterator _map_it;
        iterator begin()
        iterator end()
        const_iterator begin() const
        const_iterator end()   const
        nn_iterator nn_begin( int i )
        nn_iterator nn_end( int i )
        Graph()
        ~Graph()
        Graph & subgraph( std::set< int > & nodes )
        int num_nodes()
        int num_links()
        int degree( int i )
        double avrg_degree()
        bool has_node( int i )
        bool has_nn( int i , int j )
        bool has_link( int i , int j )
        void add_node( int i )
        void add_link( int i , int j )
        void del_link( int i , int j )
        void del_node( int i )
        void clear_node( int i )
        #private:
            #t_node_to_nn    _node_to_nn;
            #int             _num_links;

std::ostream& operator<<( std::ostream& os , Graph & G )

# === Python Wrapper for the C++ Graph class ===

cdef class PyGraph:

    # === Data-members ===

    # Pointer to a C++ Graph object.
    cdef Graph * _c_graph

    # === Function-members ===    

    # @ graph.pyx

以及cython .pyx文件:

And the cython .pyx file:

# file : graph.pyx

# === Cython cimports ===

from libcpp cimport bool
from libcpp.set cimport set as cset
from libcpp.map cimport map as cmap
from cython.operator cimport dereference as deref, preincrement as inc

# === Ctypedefs for Graph class ===

# @ graph.pxd

# === Exposing the C++ Graph class ===

cdef extern from "cpp_graph2.h":
    cdef cppclass Graph:
        #public:
        ctypedef cset[ int ]                     t_nn
        ctypedef cset[ int ].iterator            nn_iterator
        ctypedef cmap[ int , t_nn ]              t_node_to_nn
        cppclass iterator:
            #friend class Graph;
            #public:
            typedef iterator self_type
            typedef int value_type
            typedef int & reference
            typedef int * pointer
            typedef t_node_to_nn::iterator map_iterator
            typedef std::forward_iterator_tag iterator_category
            iterator( map_iterator map_it )
            self_type operator++()
            self_type operator++(int junk)
            value_type    operator*()
            Graph::t_nn * operator->()
            bool operator==( const self_type & rhs )
            bool operator!=( const self_type & rhs )
            #private:
            #    map_iterator _map_it;
        cppclass const_iterator:
            #friend class Vertex;        
            #public:
            typedef const_iterator self_type
            typedef int value_type
            typedef int & reference
            typedef int * pointer               
            typedef t_node_to_nn::iterator map_iterator
            typedef std::forward_iterator_tag iterator_category
            const_iterator( map_iterator map_it )
            self_type operator++()
            self_type operator++(int junk)
            const value_type    operator*()
            const Graph::t_nn * operator->()
            bool operator==( const self_type& rhs )
            bool operator!=( const self_type& rhs )
            #private:
            #    map_iterator _map_it;
        iterator begin()
        iterator end()
        const_iterator begin() const
        const_iterator end()   const
        nn_iterator nn_begin( int i )
        nn_iterator nn_end( int i )
        Graph()
        ~Graph()
        Graph & subgraph( std::set< int > & nodes )
        int num_nodes()
        int num_links()
        int degree( int i )
        double avrg_degree()
        bool has_node( int i )
        bool has_nn( int i , int j )
        bool has_link( int i , int j )
        void add_node( int i )
        void add_link( int i , int j )
        void del_link( int i , int j )
        void del_node( int i )
        void clear_node( int i )
        #private:
            #t_node_to_nn    _node_to_nn;
            #int             _num_links;

# === Python Wrapper for the C++ Graph class ===

cdef class PyGraph:

    # === Data-members ===    

    # @ graph.pxd

    # === Function-members ===    

    def __cinit__( self ):

        self._c_graph = new Graph()

    def __dealloc__( self ):

        del self._c_graph

    # TODO : implement the methods for adding and deleting nodes/links.

最后,当我尝试编译/构建它时,出现以下错误:

Finally, when I attempt to compile/build this, I get the following error:

###########################################################
# setup build_ext...
###########################################################

Error compiling Cython file:
------------------------------------------------------------
...
# === Exposing the C++ Graph class ===

cdef extern from "cpp_graph2.h":
    cdef cppclass Graph:
        #public:
        ctypedef cset[ int ]                     t_nn
       ^
------------------------------------------------------------

ExcessDegreeModel/graph.pxd:51:8: Expected an identifier, found 'ctypedef'
...

推荐答案

我已经使用namespace关键字指定了嵌套的声明,从而获得了嵌套定义.例如,如果您有名为mystuff.hpp的C ++标头中的以下内容:

I have gotten nested definitions to work using the namespace keyword, specifying the nested declaration. Like, if you have e.g. the following in a C++ header named mystuff.hpp:

namespace MyStuff {
    struct Outer {
        struct Inner {
            int value;
        };
        Inner member;
    };
}

...您可以像这样巩固这些结构:

… you can encython those structures like so:

cdef extern from "mystuff.hpp" namespace "MyStuff::Outer":
    cppclass Inner:
        int value

cdef extern from "mystuff.hpp" namespace "MyStuff":
    cppclass Outer:
        Inner member

…如果您实际上将C ++领域中的所有内容都包裹在命名空间中(如编写的那样),则它读起来会更连贯(否则,第二个cdef的声明中没有namespace,这看起来更像IMO).

… it reads more coherently if you actually have everything in C++-land wrapped in a namespace, as written (otherwise the second cdef has no namespace in its declaration, which looks wierder IMO).

我有许多在现实世界中工作的示例:此处是一个示例

I have a number of real-world currently-working examples of this: one such example is here, another one is here.

这篇关于Cython:使用嵌套的typedef公开C ++类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆