0

I am writing a C++ wrapper class for generating uniform distributions for integer and floating-point types using the <random> library. I created an abstract base class which the specialised classes for the two types would derive from. However, I can only access the members of the base class via the this pointer. This is not what I expected, as I thought derived classes could directly access their base class's protected members. Can someone explain if there is a nuance I'm missing here? My code is shown below.

Note: the function GetTypeCategory() simply categorises all integer types together and likewise for the floating-point types. It return an enumerator of type TypeCategory.

/** Random base class. */
template <typename data_type, TypeCategory type_category = GetTypeCategory(data_type())>
class RandomBase
{
  protected:
  std::random_device Device; /** Random device. */
  std::mt19937 Generator;    /** Random number generator. */

  /** Protected constructor. */
  RandomBase() : Generator(Device()) {};

  public:
  /** Virtual destructor. */
  virtual ~RandomBase() {};

  /** Pure virtual random number generating method. */
  virtual inline data_type Get() = 0;
};

/** Forward declaration of the specialised Random classes. */
template <typename data_type, TypeCategory type_category = GetTypeCategory(data_type())>
class Random;

/** Random integer class. */
template <typename data_type>
class Random<data_type, TypeCategory::Integer> : public RandomBase<data_type, TypeCategory::Integer>
{
  private:
  std::uniform_int_distribution<data_type> Distribution;

  public:
  Random() = delete;
  Random(const data_type& _min, const data_type& _max) : RandomBase<data_type, TypeCategory::Integer>(), Distribution(_min, _max) {}
  ~Random() = default;

  inline data_type Get() { return Distribution(this->Generator); }
//  inline data_type Get() { return Distribution(Generator); } // This does not compile as Generator is not visible from Random
};

/** Random floating-point class. */
template <typename data_type>
class Random<data_type, TypeCategory::FloatingPoint> : public RandomBase<data_type, TypeCategory::FloatingPoint>
{
  private:
  std::uniform_real_distribution<data_type> Distribution;

  public:
  Random() = delete;
  Random(const data_type& _min, const data_type& _max) : RandomBase<data_type, TypeCategory::FloatingPoint>(), Distribution(_min, _max) {}
  ~Random() = default;

  inline data_type Get() { return Distribution(this->Generator); }
//  inline data_type Get() { return Distribution(Generator); } // This does not compile as Generator is not visible from Random
};

/** Template argument deduction guide for the Random class. */
template <typename data_type> Random(data_type, data_type) -> Random<data_type>;
niran90
  • 248
  • 1
  • 10
  • 2
    Because the language says so... And because if you want to transparently access a protected data member of a base class, you can use a `using` directive to import its symbol into the subclass namespace. – Serge Ballesta Sep 30 '21 at 06:37
  • 3
    It's because the base class depends on a template parameter, and the name lookup needs a little guidance in that case. (It doesn't work with public members either.) – molbdnilo Sep 30 '21 at 06:38
  • 1
    Please read about the [mcve]. – molbdnilo Sep 30 '21 at 06:42
  • 2
    Does this answer your question? [Derived template-class access to base-class member-data](https://stackoverflow.com/questions/1120833/derived-template-class-access-to-base-class-member-data) – Const Sep 30 '21 at 06:57
  • @molbdnilo Thanks for the advice. I'm pretty new to posting on SO. – niran90 Sep 30 '21 at 07:30
  • @Const Yes, it does. Thank you. – niran90 Sep 30 '21 at 07:31

0 Answers0