1

我正在尝试编写一个容器,该容器能够对对象进行分类并存储分类函数为真的指针。

我的问题是,它无法编译,并且由于我对std::functionor之类的可调用对象缺乏经验lambdas,因此我不确定如何修复它。

我想要这样一个容器,因为我需要经常获取一些“类别”——这使得缓存结果变得容易。特别是在本例中,如果Dogs 更改了它们的sound,则可以简单地重新创建类别(因为可调用对象仍然存在)。

更重要的是,我对提供良好性能的解决方案感兴趣。正如我所读到的,std::functions 不太可能是inlined。有没有办法提供inlined 性能?

编译器说:

main.cpp: In function 'int main()':
main.cpp:51:108: error: no matching function for call to 'CategoryContainer<Dog>::addCategory(CategoryContainer<Dog>::Categories, main()::<lambda(auto:1&)>)'
     dogs.addCategory( CategoryContainer<Dog>::Categories::Wuff, [](auto& d){return d.makeSound()=="Wuff";} );

main.cpp:39:10: note: candidate: void CategoryContainer<T>::addCategory(CategoryContainer<T>::Categories, std::function<bool()>) [with T = Dog]
     void addCategory(Categories cat, std::function<bool()> f) {
main.cpp:39:10: note:   no known conversion for argument 2 from 'main()::<lambda(auto:1&)>' to 'std::function<bool()>'

main.cpp: In lambda function:
main.cpp:52:71: error: expected '{' before '(' token
     dogs.addCategory( CategoryContainer<Dog>::Categories::WauWau, []()(auto& d){return d.makeSound()=="WauWau";} );

main.cpp: In function 'int main()':
main.cpp:52:72: error: expected primary-expression before 'auto'
     dogs.addCategory( CategoryContainer<Dog>::Categories::WauWau, []()(auto& d){return d.makeSound()=="WauWau";} );

这是我的代码:

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <functional>

class Dog
{
public:
    std::string makeSound() { return _sound; }
    void setSound(std::string sound) { _sound=sound; }
private:
    std::string _sound = "Wuff";
};

template<class T>
class CategoryContainer
{
public:
    using objectContainer = std::vector<T>;
    using pointerContainer = std::vector<T*>;

    enum class Categories { Wuff, WauWau }; // Dogs are e.g. destinguished by the sound they make.

    struct Category {
        std::function<bool()> func;
        pointerContainer pointers;
        Category(std::function<bool()> f, objectContainer& data) : func(f) {
            for(auto& i : data)
                if( func(i) )
                    pointers.emplace_back(&i);
        }
    };

    CategoryContainer(size_t n) {
        data.resize(n); // Construct so many dogs.
    }

    void addCategory(Categories cat, std::function<bool()> f) {
        indexed[cat] = Category(f, data);
    }

private:
    objectContainer data;
    std::unordered_map<Categories, Category> indexed;
};

int main()
{
    CategoryContainer<Dog> dogs(10);
    dogs.addCategory( CategoryContainer<Dog>::Categories::Wuff, [](auto& d){return d.makeSound()=="Wuff";} );
    dogs.addCategory( CategoryContainer<Dog>::Categories::WauWau, []()(auto& d){return d.makeSound()=="WauWau";} );
}
4

2 回答 2

2

[](auto& d){return d.makeSound()=="Wuff";}您作为函子传递,但addCategory被声明为

void addCategory(Categories cat, std::function<bool()> f) {

所以函子应该接受零个参数,但实际上one.std::function<bool()>你应该使用而不是std::function<bool(const T&)>

于 2016-11-25T16:32:12.317 回答
1

正如 Alexey Guseynov (+1) 所指出的,您的func()inCategory收到了一个T对象。

因此,正如建议的那样,应该是std::function<bool(T const &)>.

你必须在三点上纠正这一点:

1)std::function<bool()> func;成为std::function<bool(T const &)> func;

2)Category(std::function<bool()> f, objectContainer& data) : func(f)成为Category(std::function<bool(T const &)> f, objectContainer& data) : func(f)

3)void addCategory(Categories cat, std::function<bool()> f)成为void addCategory(Categories cat, std::function<bool(T const &)> f)

但还不够。

现在, 的makeSound()方法与lambdaDog函数中的 const实例化一起使用。Dog所以makeSound()(不修改对象)应该在const方法中修改

std::string makeSound() const { return _sound; }

在这一点上我有一些错误,因为Dogs不兼容std::unordered_map因为(如果我理解正确的话)没有专门的std::hash<CategoryContainer<Dog>::Categories>

但是,为了避免这个问题,如果你可以改变

std::unordered_map<Categories, Category> indexed;

有序std::map#include <map>也添加)

std::map<Categories, Category> indexed;

如果你改变,在addCategory(),行

indexed[cat] = Category(f, data);

由于我不想进一步调查的原因(涉及构造函数)而给出错误,

indexed.emplace(std::piecewise_construct,
                std::forward_as_tuple(cat),
                std::forward_as_tuple(f, data));

你应该能够编译你的例子。

于 2016-11-25T19:33:33.597 回答