1

For indexing I use std::unordered_map and std::map. Both of them throws compiling errors when using as follow:

std::unordered_map<std::function<bool(Ent*)>, int> var;

std::unordered_map fails due referencing deleted function

std::map fails due no < operator

The ideal solution for me would be to use a type of map, but if is a must to use another type of container, then it shouldn't be a problem

uIM7AI9S
  • 353
  • 4
  • 13
  • Given a `std::function – François Andrieux Mar 09 '20 at 19:48
  • 1
    Values in an unordered_map must be: 1) hashable, 2) comparable for equality. Each `std::function` is a unique class by itself, and there is no hash function defined for `std::function`s. Sorry, but C++ can't work the way you want it to work. Can you define exactly what you mean by "indexing"? – Sam Varshavchik Mar 09 '20 at 19:48
  • I just want to be able to do stuff like `auto tmp = var[someFct]` in an efficient way – uIM7AI9S Mar 09 '20 at 19:51
  • 4
    I'm curious what the use case for this is? Also does it have to be a std::function or can it just be function pointers? – Borgleader Mar 09 '20 at 19:51
  • but why functions? Why not `auto tmp = var[someKey]` where `someKey` is not a function? – 463035818_is_not_an_ai Mar 09 '20 at 19:52
  • I plan to use `var` as a set of rules where the final result is positive if every `std::function` from the map returns `true` of how times the second element in pair describes. I can use pointers of `std::function` – uIM7AI9S Mar 09 '20 at 19:54
  • 1
    That doesn't sound like a map to me. This is not what maps are for. – Sam Varshavchik Mar 09 '20 at 19:54
  • 1
    I think you'd be much better off using `vector>` or `vector, int>>`, and implementing the logic you want yourself. Also, on a side note, you should prefer `function` unless your "rules" really need to modify the objects they are passed. – alter_igel Mar 09 '20 at 19:58
  • Thx for the suggestions with pointers or pair. They look good and I'll use one of them since seems like `std::map` isn't fitted for this job – uIM7AI9S Mar 09 '20 at 20:02
  • [In which scenario do I use a particular STL container?](https://stackoverflow.com/questions/471432/in-which-scenario-do-i-use-a-particular-stl-container) – SacrificerXY Mar 09 '20 at 20:02
  • Very useful. Though it leads me to `std::map`, or more indulgently to `std::set` – uIM7AI9S Mar 09 '20 at 20:07
  • 1
    I'm not sure the intent here is at all clear. In what way would you want to select an entry from the map based on which function it uses? The question doesn't really make sense to me. – Gem Taylor Mar 09 '20 at 20:42
  • Can you please explain in more detail what exactly you're trying to achieve? I appreciate your previous comment but I'm having a lot of trouble understanding what you mean. A little bit of pseudocode demonstrating how you want to use this data structure would improve this question a lot. Please [edit] your original post to make such improvements. Otherwise, I believe this is a case of the [XY Problem](https://en.wikipedia.org/wiki/XY_problem) and cannot be answered in a helpful or meaningful way. – alter_igel Mar 09 '20 at 22:00
  • I tried to not wrap the question around a context. If I can get value by key using `[]` operator is enough – uIM7AI9S Mar 10 '20 at 10:34

1 Answers1

1

One way of having functions as container key is to wrap them into functor structure

#include <unordered_map>
#include <typeinfo>

struct FunctorSum {
    int operator()(int x, int y) {
        return x + y;
    }
};
struct FunctorMult {
    int operator()(int x, int y) {
        return x * y;
    }
};

int main() {
    std::unordered_map<size_t, int> funcToInt;
    funcToInt[typeid(FunctorSum).hash_code()] = 0;
    funcToInt[typeid(FunctorMult).hash_code()] = 1;

    return 0;
}

Here I used typeid as hash, but it can also be hardcoded into functor struct.

Another way is to use std::function::target_type to calculate hash of the function, which will work only with lambdas. But you can always wrap any function into lambda.

#include <iostream>
#include <functional>

using FuncType = std::function<bool(int)>;
bool x(int v) { return v == 0; }

std::string hash(FuncType f) {
    return f.target_type().name();
}

int main() {
    auto y = [](int v) { return v == 1; };
    auto z = [](int v) { return v == 2; };

    std::cout << "x: " << hash(x) << std::endl;
    std::cout << "y: " << hash(y) << std::endl;
    std::cout << "z: " << hash(z) << std::endl;

    return 0;
}

Output

x: PFbiE
y: Z4mainEUliE_
z: Z4mainEUliE0_
Tarek Dakhran
  • 2,021
  • 11
  • 21
  • 1
    Note the warning stated [here](https://en.cppreference.com/w/cpp/types/type_info/hash_code): "No other guarantees are given: type_info objects referring to different types may have the same hash_code (although the standard recommends that implementations avoid this as much as possible) ..." – AVH Mar 09 '20 at 21:31
  • @Darhuuk, great catch. I've added second way to hash functions, which I just found. – Tarek Dakhran Mar 09 '20 at 21:37
  • 1
    The second way will only work as I would expect it to when only lambdas are used. Any non-lambda function with the same signature will "hash" to the same value. – AVH Mar 09 '20 at 21:49
  • Your c++ knowledge is amazing. Will update the answer again. – Tarek Dakhran Mar 09 '20 at 21:51
  • 1
    The problem was solved already by using pointers. I will mark this as the right answer for the effort and the fact that this is a solution – uIM7AI9S Mar 10 '20 at 10:35