I'm trying to write a container that is able to categories objects and store pointers for which a categorisation function is true.
My problem is, that it does not compile and since I'm inexperienced in regard to callables like std::function
or lambdas
, I'm not sure how to fix it.
I want such a container, since I've the need to get some "Categories" often - and this makes it easy to cache the results. Especially if, in this example, the Dog
s change their sound
, the Categories can simply be recreated (since the callable is still there).
What is more, I'm interested in a solution that delivers good performance. As I read, std::function
s are unlikely to be inline
d. Is there a way to deliver inline
d-performance?
The compiler says:
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";} );
And here is my code:
#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";} );
}