C++: Как заставить функцию принимать объект с тем же именем класса из любого пространства имен?

MainClass.h:

namespace Alpha{ enum class Parameters; }
namespace Beta { enum class Parameters; }
MainClass{
public:
  enum class Type{ Type_A, Type_B };
  MainClass(const Type t);

  void DoStuff(const Parameters p);
private:
  void doesStuff(const int p_val);
};

MainClass.cpp:

/* define values for Alpha::Parameters, Beta::Parameters here or elsewhere, and included */
MainClass::MainClass(const Type t){
  /* not sure how to do this. But essentially by switching based on 't' use either Alpha::Parameters or Beta::Parameters */
}

MainClass::DoStuff(const Parameters p){
  int p_value = static_cast<int>(p);
  doesStuff(p_value);
}

Это то, что я хотел бы сделать. Это возможно? Реально было бы неплохо, если бы класс enum вел себя как класс с наследованием, но я знаю, что не могу этого сделать. Чем больше я пытаюсь переписать это, оно просто продолжает набирать обороты, пока мне практически не придется писать конкретные классы для каждого случая (у меня в этом примере больше, чем два). Но на самом деле код очень похож.

Я также знаю, что альтернативой было бы просто позволить DoStuff (const Parameters p) быть просто DoStuff(const int p_val) и выполнять статическое приведение извне... но тогда я должен выполнить все статическое приведение в другом месте, и я не Получите хорошую проверку типов в классе enum.

Если это невозможно, это нормально... но очень плохо, если так.

2 ответа

Решение

Вы пробовали шаблон?

class Main {
    template < typename PARAMETERS >
    void DoStuff(const PARAMETERS p) {
        doesStuff(static_cast<int>(p));
    }
}

Затем вы можете предоставить специализации для каждого типа параметров, если это необходимо.

Я пропустил первую часть об определении, какой T в конструкторе. Обычно я реализую его с помощью шаблона класса, например так:

#include <iostream>

namespace Alpha{ enum class Parameters { A, B, C }; }
namespace Beta { enum class Parameters { a, b, c }; }

template < typename P >
class MainClass{
public:
    MainClass() { }

    void DoStuff(const P p) {
        int p_value = static_cast< int >(p);
        doesStuff(p_value);
    }

private:
    void doesStuff(const int p_val) {
        std::cout << "DoesStuff " << p_val << std::endl;
    }
};

int main(int argc, const char** argv) {

    MainClass< Alpha::Parameters > alpha;
    alpha.DoStuff(Alpha::Parameters::A);
    alpha.DoStuff(Alpha::Parameters::B);
    alpha.DoStuff(Alpha::Parameters::C);
    MainClass< Beta::Parameters > beta;
    beta.DoStuff(Beta::Parameters::a);
    beta.DoStuff(Beta::Parameters::b);
    beta.DoStuff(Beta::Parameters::c);
    return 0;
}

Однако, если DoStuff является единственной частью, зависящей от того, какие параметры использовать, я бы использовал функцию шаблона.

Этого можно добиться с помощью перегрузки функций и минимального кода тела функции.

MainClass::DoStuff(Alpha::Parameters p){
    int p_value = static_cast<int>(p);
    doesStuff(p_value);
}
MainClass::DoStuff(Beta::Parameters p){
    int p_value = static_cast<int>(p);
    doesStuff(p_value);
}
MainClass::DoStuff(Etcetera::Parameters p){
    int p_value = static_cast<int>(p);
    doesStuff(p_value);
}

И вся реализация будет в doesStuff() функция.

Это все равно позволит вам сохранить существующие вызовы функций, которые используют разные перечисления.

Однако такая проверка типов может быть не такой полезной, как вы думаете... этот код предполагает, что все перечисления будут одинаковыми. Если вы когда-нибудь измените только один из них (например, просто перечисление Beta::Parameters), он сломает этот код, и вы внесете ошибку без предупреждения.

Другие вопросы по тегам