如何在不使用索引

时间:2015-12-27 17:03:24

标签: python c++ swig

我对SWIG和C ++有些新意,所以这可能很明显,但我似乎无法弄明白。我有一个C ++集合对象(在MWE中,Pantry),在C ++中由std::string索引,但迭代对象。这适用于使用基于范围的for循环的C ++,其实现为begin()end()

这是一个MWE:

pantry.i

%module(directors="1") my_collection
%include "stdint.i"
%include "std_string.i"
%include "std_shared_ptr.i"
%include "std_vector.i"
%{
#include "my_collection.cpp"
%}
%nodefaultctor;
%shared_ptr(Food);
%include "my_collection.cpp"

pantry.cpp

#pragma once

#include <string>
#include <vector>
#include <map>
#include <memory>
#include <sstream>

#ifdef SWIG

%define TO_STRING()
    %extend {
        %feature("python:slot", "tp_repr", functype="reprfunc") to_string;
    }
    std::string to_string()
%enddef

%define SUBSCRIPT(return_type, subscript_type)
    %feature("python:slot", "mp_subscript", functype="binaryfunc") __getitem__;
    %extend {
        return_type __getitem__(subscript_type key) {
            return (*($self))[key];
        };
    };
    return_type operator[](subscript_type key)
%enddef

#else

#define TO_STRING() \
        std::string to_string()

#define SUBSCRIPT(return_type, subscript_type) \
        return_type operator[](subscript_type key)

#endif


class Food {
public:

    std::string name;

    Food(std::string name) {
        this->name = name;
    };

    TO_STRING() {
        std::ostringstream stream;
        stream << "<Food " << this->name << ">";
        return stream.str();
    };

};

class Pantry {
private:

    // _foods is not grammatically correct
    std::map<std::string, std::shared_ptr<Food>> _food_map;
    std::vector<std::shared_ptr<Food>> _food_vec;

public:
    Pantry() {
    };

    std::shared_ptr<Food> add(std::string name) {
        auto food = std::shared_ptr<Food>(new Food(name));
        this->_food_map[food->name] = food;
        this->_food_vec.push_back(food); // p.s., how do I prevent making a copy?
        return food;
    };

    SUBSCRIPT(std::shared_ptr<Food>, std::string) {
        return this->_food_map.at(key);
    };

    TO_STRING() {
        return "<Pantry>";
    };

    std::vector<std::shared_ptr<Food>>::const_iterator begin() {
        return this->_food_vec.begin();
    };

    std::vector<std::shared_ptr<Food>>::const_iterator end() {
        return this->_food_vec.end();
    };

    size_t size() {
        return this->_food_vec.size();
    };

};

我还整理了一个简短的Python脚本:

import pantry
pant = mc.Pantry()
print(pant.add('Bacon'))
print(pant.add('Cheese'))
print('subscript[Bacon]: {}'.format(pant['Bacon']))
for food in pant:
    print('iter: ... {}'.format(food))

然后,根据-builtin标志是否传递给SWIG,我收到错误:

  • 没有-builtinTypeError: in method 'Pantry___getitem__', argument 2 of type 'std::string' - 这是有道理的,因为我选择按字符串索引
  • -builtinTypeError: 'my_collection.Pantry' object is not iterable - 我认为这是由SWIG引起的,没有隐式创建我尚未声明的方法,这在这个实例中似乎是正确的。 / LI>

如何在不显式调用方法的情况下迭代集合内容?我意识到我可以让_food_vec公开并迭代它,但我的实际代码更复杂,我宁愿不这样做。同样,我可以实现其他一些.iterate()方法,但我已经使用begin()end()完成了工作。

编辑:我可以实现与目标语言无关的方法,类似于我为TO_STRING()SUBSCRIPT制作的宏,以及什么是正确的要添加到界面文件的模板(类似于%template(FoodIterator) std::vector<Food>::iterator;

1 个答案:

答案 0 :(得分:0)

您有two options来实现可迭代接口:

  1. 实现__iter__(),返回具有next()
  2. 的对象实例
  3. 实施__getitem__(),接受 integers or slice objects
  4. 我想这应该解释这两个错误,并提供如何解决的线索。