Faced with a challenge, the solution to which I can not resist the second day.
Below is a brief description of the task, the solution of which I ask to leave behind me .

Questions:

1. How to check the presence of the stored implementation of multimethods in this case?
2. Is it possible to solve this problem in my own way? If not, how to correctly organize the algorithm for solving this problem?
3. Is it correct to use map here?
4. How correctly to run through all the first values ​​in map for comparison with std :: pair and call the file stored in the map via a pointer to it with parameters from this very std :: pair?
5. Please point out my mistakes and explain how to correctly

addImpl — добавляет реализацию мультиметода для двух типов, которые заданы через std::type_info. hasImpl — принимает два указателя и проверяет, есть ли реализация мультиметода для соответствующих типов. call — принимает два указателя и вызывает для них соответствующую реализацию. 

* The implementation of these methods should correctly handle the situation when the multimethod is commutative

 // Base - базовый класс иерархии // Result - тип возвращаемого значения мультиметода // Commutative - флаг, который показывает, что // мультиметод коммутативный (т.е. f(x,y) = f(y,x)). template<class Base, class Result, bool Commutative> struct Multimethod2 { // устанавливает реализацию мультиметода // для типов t1 и t2 заданных через typeid // f - это функция или функциональный объект // принимающий два указателя на Base // и возвращающий значение типа Result void addImpl( ... t1, ... t2, ... f ) { } // проверяет, есть ли реализация мультиметода // для типов объектов a и b bool hasImpl(Base * a, Base * b) const { // возвращает true, если реализация есть // если операция коммутативная, то нужно // проверить есть ли реализация для b и а return ...; } // Применяет мультиметод к объектам // по указателям a и b Result call(Base * a, Base * b) const { // возвращает результат применения реализации // мультиметода к a и b return ...; } }; 

Further, my reasoning.
1. To store the implementation of the multimethod we will use the private field of this class. This will be a map with a type_index pair and a pointer to the function, which is implemented via std :: function

  using FunFObj = std::function <Result(Base*, Base*)>; private: std::map< std::pair<std::type_index, std::type_index>, FunFObj > MultData; }; 

2. Addition is realizable for two cases.

  void addImpl(std::type_info const & t1, std::type_info const & t2, FunFObj f) { if (!Commutative) MultData.insert(std::make_pair<t1, t2>, f); if (Commutative) { MultData.insert(std::make_pair<t2, t1>, f); MultData.insert(std::make_pair<t1, t2>, f); } } 

3. But I don’t know how to compare std :: pair from map with data in hasimpl and call.

  • Equal-unequal operators are defined for std :: type_info, so it shouldn’t be a problem to check for equality, but more or less, you won’t work out ... you can define a smart operator more precisely, but this is logically contradictory: how one type may be more than another. For such a case, replace map with a list. - Andrej Levkovitch
  • @AndrejLevkovitch and why more-less? The goal is to compare equally-unequal objects from the stored std :: pair (there are two std :: type_info) with the resulting two typeid (a) and typeid (b) of the type Base *. (it-> first == PairThis) return it-> second (a, b); Something like this, but this design does not work - AlexIdest
  • @Andrej Levkovitch: What does “more-less fail”? Especially for more or less, type_info has a before method. Another thing is that more or less is not needed here. - AnT
  • @AnT the inquirer wants to use type_info (a pair of them) in the map , and for him, just the same, this is necessary (at least by default less if no other comparison function is specified). - Andrej Levkovitch
  • @AndrejLevkovitch Great. So, for the implementation of the ordering comparison, there is a before method, which orders all type_info . Those. There are no difficulties with this - compare to health. - AnT

1 answer 1

I thought of leaving a comment, but then I decided that it was pulling the answer (or at least part of it).

I'll start with the fourth paragraph:

By map do not need to бегать - this is a binary search tree, so if you need to find the value that is stored in map by key , then you can do this:

 auto any_value = some_map[key]; 

The tree is implemented in such a way that, regardless of the amount of stored data, this will always have logarithmic complexity. True, the way I got value suitable only if you are sure that it is there, because if it is not there, it will be created using the default constructor. If this does not suit you, then use

 some_map.at(key); 

However, note that if key absent, you will get an out_of_range exception, so wrap it in try-catch . But in general, it is better to use find - the fact is that this operation is almost as fast as the previous ones, but in this case you are not dependent on which container you will use (you can replace it with a list and not even notice the difference, unless do not work with large amounts of data).

Now to 3: No, not true. First, start with the fact that map orders elements (by default) using the < operator, which means that the keys must support this operation (you can also use your own operation, but this is a different story). You use std::type_info which has operators == & != . You can, of course, define smart-assisted comparison operators for this type, but this is illogical (as one type may be larger than the other), so you better use not the map but the list. At least for such "keys". If you decide to use other keys, if they support the comparison operation, you can use the map (if you use the list correctly, replacing it with map is changing std::list to std::map during initialization).

1) The implementation, if I understand correctly, is std::function , and for it the operators are equal-unequal, but less-more is not. But in any case, it will be stored as value so they are not needed.

In general, the idea is correct, at least I would do in a similar way.

UDP

As I looked at type_info there is a hash_code , and this suggests that you can use std::unorder_map - not for nothing did this container be entered.

UDP

In connection with the update of the first item. Everything should be pretty simple here: if you need to check for the presence of a value for a key , then just try to find the key

  if (som_kont.find(key) != som_kont.end()) { // founded } else { // not founded } 
  • Yes, the implementation of the multimethod is really stored in std :: function. But that's why the implementation is to compare? We either add this implementation in method 1, or in method 2 we look for the corresponding pairs for the transferred types, or we call the stored multimethod of method 3. - AlexIdest
  • @AlexIdest Well, did you ask the question (1 point) or not? Or you can be sealed, or what? - Andrej Levkovitch
  • You are absolutely right. My mistake, it was necessary to write "How to check the presence of implementation", and not "how to compare." I'll fix it now - AlexIdest