Вызов функции из другого класса из unordered_multimap? - PullRequest
0 голосов
/ 05 апреля 2019

Это связано с моим последним постом, который вы можете найти здесь: Создание unordered_map для std :: functions с любыми аргументами . Теперь я пошел дальше и распространил это на занятия. Допустим, у меня есть три разных класса. И у всех этих классов разные методы, кроме getVariable() и setVariable(int). Таким образом, для этого примера мы будем классифицировать их ClassA, ClassB и ClassC.

У меня также есть базовый класс, который я хочу использовать в качестве драйвера. По сути, если я хочу установить переменную между ClassA и ClassC, я бы вызвал функцию setVariable базового класса.

#ifndef BASE_CLASS_HPP
#define BASE_CLASS_HPP

#include <unordered_map>
#include <functional>
#include <utility>
#include <string>
#include <any>

template<class A, class B>
class BaseClass
{
  public:
    BaseClass() { bindThem(); }

    std::pair<int,int> getValue()
    {
      // return classA and ClassB's values
    }

    void setValue(int newVal)
    {
      auto iter = functions.equal_range("setValue");
      std::any_cast<void(*)(int)>(mapIter->second)(newVal);
    }
  private:
    std::unordered_multimap<std::string,std::any> functions;

    void bindThem()
    {
      functions.emplace("setValue",&A::setValue);
      functions.emplace("setValue",&B::setValue);
      functions.emplace("getValue",&A::getValue);
      functions.emplace("getValue",&B::getValue);
    }

};

У меня тогда в основном:

#include <iostream>

#include "baseClass.hpp"
#include "classA.hpp"
#include "classB.hpp"
#include "classC.hpp"

int main()
{
  ClassA a;
  ClassB b;
  ClassC c;

  c.setValue(20);

  BaseClass<ClassA,ClassB> base1;
  BaseClass<ClassA,ClassC> base2;

  base1.setValue(15);

  auto values = base1.getValues();


}

Я могу разместить функции внутри своей карты, однако, когда я пытаюсь any_cast, я ничего не получаю взамен. Я тоже попробовал:

std::any_cast<void(A::*)(int)>(mapIter->second)(newVal);

Но это также дает мне ошибку компилятора, которую необходимо использовать. * Или -> *, и я попробовал все, чтобы заставить его скомпилироваться, и я действительно не знаю, что я делаю неправильно. Я также понял, что если бы я назвал это так, то я бы не смог получить доступ к функции B setVariable, так как я использую пространство имен A's.

Можно ли как-нибудь заставить это работать так, как я хочу? По сути, я пытаюсь изменить эти значения классов без необходимости делать какие-либо копии этих классов и вместо этого напрямую изменять их из этого драйвера.

1 Ответ

0 голосов
/ 05 апреля 2019

Я до сих пор не совсем понимаю назначение такой структуры, но здесь есть вариант, как сделать ее хотя бы скомпилированной:

#include <unordered_map>
#include <functional>
#include <utility>
#include <string>
#include <any>

template<class A, class B>
class BaseClass
{
  public:
    BaseClass() { bindThem(); }

    std::pair<int,int> getValue()
    {
      auto range = functions.equal_range("getValue");
      return 
        {
          (a.*std::any_cast<int(A::*)()>(*range.first))(),
          (b.*std::any_cast<int(B::*)()>(*range.second))()
        };
    }

    void setValue(int newVal)
    {
      auto range = functions.equal_range("setValue");
      (a.*std::any_cast<void(A::*)(int)>(*range.first))(newVal);
      (b.*std::any_cast<void(B::*)(int)>(*range.second))(newVal);
    }
  private:
    std::unordered_multimap<std::string,std::any> functions;

    void bindThem()
    {
      functions.emplace("setValue",&A::setValue);
      functions.emplace("setValue",&B::setValue);
      functions.emplace("getValue",&A::getValue);
      functions.emplace("getValue",&B::getValue);
    }

    A a;
    B b;
};

class ClassA
{
public:
    void setValue(int){}
    int getValue() {return 0;}
};

class ClassB
{
public:
    void setValue(int){}
    int getValue() {return 1;}
};

int main()
{
    BaseClass<ClassA, ClassB> x;
    x.setValue(3);
    auto i = x.getValue();
}

Обратите внимание на несколько вещей:

  1. Я добавил членов в BaseClass, так как для вызова функций-членов вам нужен вызываемый объект.
  2. Я использую первый и последний итераторы диапазона от equal_range, но порядок элементов в этом диапазоне определяется реализацией. Поэтому, чтобы все заработало, вам нужно позаботиться о том, чтобы определить, какой элемент контейнера соответствует классу A, а какой классу B.
...