class Base{ ClassName::units_type units; public:" /> class Base{ ClassName::units_type units; public:" /> class Base{ ClassName::units_type units; public:"/>

C++ Template using an enum defined by a derived class

76 views Asked by At

Basically here's what my "ideal" code would look like, if it were legal:

template<typename ClassName>
class Base{
     ClassName::units_type units;
public:
     Base(ClassName::units_type Units) : units(Units){};
     void SomeFunc(ClassName::units_type Units);
};

class Derived : public Base<Derived>{
public:
     enum units_type{
          meters,
          feet
     };
     using Base::Base;
};

What I really need is to be able to call it like this:

Derived d = Derived(Derived::meters);
d.SomeFunc(Derived::feet);

i.e. I need the units enum to be scoped to the derived class, and the derived class only - but also be available as a datatype in the base class.

Of course, this doesn't work.

There is a workaround in c++20, but I am looking for a c++17 solution. In c++20 I can write:

template<typename ClassName, typename units_type>
class Base{
     units_type units;
public:
     Base(units_type Units) : units(Units){};
     void SomeFunc(units_type Units){};
};

enum class DerivedUnits{
     meters,
     feet
};

class Derived : public Base<Derived, DerivedUnits>{
public:
     using enum DerivedUnits;
     using Base::Base;
};

This works great, and I can call

Derived d = Derived(Derived::meters);
d.SomeFunc(Derived::feet);

just like I want, and the world is a happy place. Is there a way - any way - to accomplish this same end-goal in C++17?

Thanks, Farley

1

There are 1 answers

1
John Zwinck On

The only part of your "workaround" solution that requires C++20 is using enum. You can easily avoid it like this:

template<typename ClassName, typename units_type>
class Base{
     units_type units;
public:
     Base(units_type Units) : units(Units){};
     void SomeFunc(units_type Units){};
};

enum class DerivedUnitsImpl{
     meters,
     feet
};

class Derived : public Base<Derived, DerivedUnitsImpl>{
public:
     using DerivedUnits = DerivedUnitsImpl;
     using Base::Base;
};