【问题标题】:Passing a callable to a object that builds some kind of multi-index container将可调用对象传递给构建某种多索引容器的对象
【发布时间】:2016-11-25 16:22:26
【问题描述】:

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

我的问题是,它无法编译,而且由于我对 std::functionlambdas 等可调用对象缺乏经验,因此我不知道如何解决它。

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

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

编译器说:

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";} );
}

【问题讨论】:

  • 一个重要但仍未得到解答的部分是编译器如何处理这种情况。非常欢迎补充这一点。

标签: c++11 lambda c++14 callable generic-lambda


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

    正如 Alexey Guseynov (+1) 所指出的,您在 Category 中的 func() 会收到一个 T 对象。

    所以,按照建议,应该是std::function&lt;bool(T const &amp;)&gt;

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

    1) std::function&lt;bool()&gt; func; 变为 std::function&lt;bool(T const &amp;)&gt; func;

    2) Category(std::function&lt;bool()&gt; f, objectContainer&amp; data) : func(f) 变成 Category(std::function&lt;bool(T const &amp;)&gt; f, objectContainer&amp; data) : func(f)

    3) void addCategory(Categories cat, std::function&lt;bool()&gt; f) 变为 void addCategory(Categories cat, std::function&lt;bool(T const &amp;)&gt; f)

    但这还不够。

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

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

    此时我有一些错误,因为Dogsstd::unordered_map 不兼容,因为(如果我理解正确的话)std::hash&lt;CategoryContainer&lt;Dog&gt;::Categories&gt; 没有专门化

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

    std::unordered_map<Categories, Category> indexed;
    

    在有序的std::map 中(也添加#include &lt;map&gt;

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-17
      • 1970-01-01
      • 2012-02-23
      • 1970-01-01
      • 2013-09-15
      • 2012-09-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多