0

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);
}

That's what I'd like to be able to do. Is this possible? Realistically it'd be nice if enum class just behaved like a class with inheritance, but I know I can't do that. The more I try to rewrite this, it just keeps spiraling out until I'd practically be left writing specific classes for each case (I have more than just the two in the example). But the code is all so similar, really.

I also know the alternative would just be to allow DoStuff(const Parameters p) to be just a DoStuff(const int p_val) and do the static cast externally... but then I have to do all the static casting elsewhere, and I don't get the nice typechecking of enum class.

If it's not possible, that's fine... but too bad if so.

shavera
  • 803
  • 1
  • 8
  • 18
  • Could you not just have a single enum with all the potential values, but then validate whether a particular value is permitted at run time and throw an exception / return an error if the value is not permitted? – Rich L Jan 06 '15 at 16:23
  • `Alpha::Parameters` and `Beta::Parameters` are as different as `Alpha_Parameters` and `Beta_Parameters`, so namespaces are irrelevant to this story. You might want to be able to pass either any enum whatsoever, or any enum from some predefined set. In both cases there are easier solutions. Perhaps enum is not the right tool for the job. – n. m. could be an AI Jan 06 '15 at 16:55

2 Answers2

3

Have you tried a template?

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

You can then provide specializations for each Parameters type if necessary.

I missed the first part about determining which T in the constructor. Typically I'd implement it with a class template, like this:

#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;
}

However, if DoStuff is the only part dependent on which Parameters to use, I'd use the template function.

Jason
  • 1,086
  • 5
  • 10
  • Ah yes I do believe this would work out for me. I hadn't thought about putting the template outside the class. I'd been considering it around the specific functions like 'DoStuff' but around the class is, I think, precisely what I'm looking for. Thanks. – shavera Jan 06 '15 at 17:39
  • Actually, I had intended the template function to be inside the class -- that provides you the most protection because the only public interface is based on the enums, not the underlying integer representation. dan-O's comment about assumptions still applies, but this should help you accomplish what you describe. – Jason Jan 06 '15 at 17:45
  • Hm, thanks, I do understand what both comments are addressing. However, in the abstraction from my real example to the posted code, some subtlety was lost that still leads me to favour the use of the templatized class. For a slightly less general case (what I'm facing) 'packet' is some generic data container that has some header information depending on what type of packet it is. The headers are slightly different from packet to packet, which is what I want to encapsulate in the 'parameters' section, byte indices for where certain values will be stored. (cont' below) – shavera Jan 06 '15 at 17:51
  • While I'd previously just made it polymorphic... the reality is that it functions much better as a templatized container with specific "tags" (the template enums) that can be specified elsewhere when it is used. – shavera Jan 06 '15 at 17:51
  • 1
    Yep, often good questions, when reduced to something simple enough to post in SO, attract holier-than-thou "why would you do something like that?" responses. That's why I try to answer the question. Good luck! – Jason Jan 06 '15 at 17:58
1

You could accomplish this with function overloading and minimal function body code.

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);
}

And all the implementation would be in the doesStuff() function.

This would still allow you to keep the existing function calls that use the different enums.

However, this typechecking may not be as valuable as you think... this code assumes that all the enums will be kept identical. If you ever change just one of them (like just the Beta::Parameters enum), it will break this code, and you will have introduced a bug without any warning.

dan-O
  • 354
  • 1
  • 10
  • Yes, this is true, I just was wondering if there were a more efficient way, I guess. I have roughly 2*6 different varieties of "Parameters" to use in my real scenario and having a 12x overloaded function seemed... tedious at best. Templatized may be better as per Jason's comment above. – shavera Jan 06 '15 at 17:37