2016-11-25 48 views
1

我正在嘗試編寫一個容器,該容器能夠爲分類函數爲true的類別對象和存儲指針。將可調用對象傳遞給構建某種多索引容器的對象

我的問題是,它不會編譯,因爲我對於像可調用或std::functionlambdas缺乏經驗,我不知道如何解決它。

我想要這樣一個容器,因爲我經常需要獲取一些「類別」 - 這樣可以很容易地緩存結果。特別是,如果在此示例中Dog更改sound,則可以簡單地重新創建類別(因爲可調用仍然存在)。

更重要的是,我對提供良好性能的解決方案感興趣。據我所知,std::function s不可能是inline d。有沒有辦法提供inline的d-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";}); 
} 
+0

重要的一點,仍然沒有答案的部分是,編譯器如何處理這種情況。除此之外,非常歡迎。 – dani

回答

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

1

正如指出的阿列克謝Guseynov(+1),你在Categoryfunc()收到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)

但是還不夠。

現在DogmakeSound()方法與您的lambda函數中的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)); 

你可以編譯你的例子。