Cython:使用嵌套的typedef公开C ++类

时间:2016-09-20 15:46:13

标签: c++ class nested cython typedef

根据stackoverflow中的this问题/答案,不可能在cython中直接重写C ++嵌套typedef。我有这样的问题,我不知道哪种是正确/最佳的方式。

让我通过一个例子来说明一点。下面,您可以找到两个C ++文件(一个header.h和一个.cpp)的内容以及两个相应的cython文件(一个.pxd和一个.pyx)。在名为cpp_graph.h的C ++头文件中,您可以看到嵌套的typedef声明;例如,对应于Graph::iterator::nn_iterator我不知道如何在相应的graph.pxd文件中公开。或者换句话说,我不知道什么是“官方”或“标准”方式它

一些相关信息。如果你检查了STL的cython包装器,你可以找到嵌套的typedef。例如utility.pxd中的herevector.pxd文件中的here。但是,ctypedef的嵌套用法仅用于模板声明。 是否嵌套typedef仅适用于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文件:

// 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文件:

# 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文件:

# 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.

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

###########################################################
# 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'
...

1 个答案:

答案 0 :(得分:2)

我已经使用namespace关键字使嵌套定义工作,指定嵌套声明。就像,如果你有例如以下名为mystuff.hpp的C ++标头中的以下内容:

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

......你可以像这样结构那些结构:

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)。

我有一些现实世界的实际例子:one such example is hereanother one is here