0

Note: Code base I am working on is C++98 standard.

I have been trying to convert this code which has been configured as structs, to a class format to be better used with the program I am working on.

In the original code, I can understand how to convert the struct interval_timer to a class (based off my research from here), however I seem to get problems when attempting to convert sections like struct abc_timer : interval_timer. I think understand that this is essenially saying "create struct abc_timer within class interval_timer, but on compile of my code I get several errors.

Original Code

#include <boost/asio.hpp>
#include <iostream>
#include <boost/bind.hpp>
using boost::posix_time::millisec;
using boost::posix_time::seconds;
typedef boost::posix_time::microsec_clock Clock;
using boost::system::error_code;

struct interval_timer
{
  interval_timer(boost::asio::io_context &io, millisec i)
      : interval(i), timer(io)
  {
    run();
  }

  virtual bool callback() = 0;

  void run()
  {
    timer.expires_from_now(interval);
    timer.async_wait(boost::bind(&interval_timer::on_timer, this, boost::asio::placeholders::error()));
  }

  void stop()
  {
    timer.cancel();
  }

private:
  void on_timer(error_code ec)
  {
    if (!ec && callback())
      run();
  }
  millisec const interval;
  boost::asio::deadline_timer timer;
};

int main()
{
  boost::asio::io_context io;

  struct abc_timer : interval_timer
  {
    abc_timer(boost::asio::io_context &io, millisec i) : interval_timer(io, i) {}
    virtual bool callback()
    {
      std::cout << "TEST_ABC" << std::endl;
      return true;
    }
  } abc(io, millisec(200));

  struct counter_timer : interval_timer
  {
    counter_timer(boost::asio::io_context &io, millisec i, interval_timer &abc)
        : interval_timer(io, i), abc(abc), current(0) {}

    virtual bool callback()
    {
      std::cout << "COUNTER AT " << ++current << std::endl;

      if (current < 5)
        return true;

      abc.stop();
      return false;
    }

  private:
    interval_timer &abc;
    int current;
  } counter(io, millisec(1000), abc);

  io.run();
}

My conversion attempt

#include <boost/asio.hpp>
#include <iostream>
#include <boost/bind.hpp>
using boost::posix_time::millisec;
using boost::posix_time::seconds;
typedef boost::posix_time::microsec_clock Clock;
using boost::system::error_code;

boost::asio::io_service io;

class Interval_Timer
{
public:
  Interval_Timer(boost::asio::io_service &io, millisec i);

  virtual bool callback() = 0;
  // boost::asio::io_service io;

public:
  void run();
  void stop();
  void on_timer(error_code ec);

  millisec const interval;
  boost::asio::deadline_timer timer;


public: 
  struct abc_timer
  {
    abc_timer(boost::asio::io_service &io, millisec i) : Interval_Timer(io, i) {}
    virtual bool callback()
    {
      std::cout << "TEST_ABC" << std::endl;
      return true;
    }
  } abc(io, millisec(200));

  struct counter_timer
  {
    counter_timer(boost::asio::io_service &io, millisec i, Interval_Timer &abc)
        : Interval_Timer(io, i), abc(abc), current(0) {}

    virtual bool callback()
    {
      std::cout << "COUNTER AT " << ++current << std::endl;

      if (current < 5)
        return true;

      abc.stop();
      return false;
    }

  private:
    Interval_Timer &abc;
    int current;
  }counter(io, millisec(1000), abc);
};

Interval_Timer::Interval_Timer()
{
}

Interval_Timer::Interval_Timer(boost::asio::io_service &io, millisec i)
    : interval(i), timer(io)
{
  run();
}

Interval_Timer::~Interval_Timer()
{
  std::cout << " DECONSTRUCTED " << std::endl;
}

void Interval_Timer::run()
{
  timer.expires_from_now(interval);
  timer.async_wait(boost::bind(&Interval_Timer::on_timer, this, boost::asio::placeholders::error()));
}

bool Interval_Timer::callback()
{
  std::cout << "TEST_ABC" << std::endl;
  return true;
}

void Interval_Timer::on_timer(error_code ec)
{
  if (!ec && callback())
    run();
}

For lines such as }counter(io, millisec(1000), abc); I get the following error:

error: ‘io’ is not a type

and

error: expected ‘)’ before numeric constant

And for initialisers:

/src/timerTest/execTimer.cpp: In constructor ‘Interval_Timer::counter_timer::counter_timer(boost::asio::io_service&, boost::posix_time::millisec, Interval_Timer&)’:
/src/timerTest/execTimer.cpp:181:11: error: type ‘Interval_Timer’ is not a direct base of ‘Interval_Timer::counter_timer’
         : Interval_Timer(io, i), abc(abc), current(0) {}
           ^
  • 3
    Maybe you weren't aware that structs and classes are basically the same thing? The only difference being that `struct` has by default, `public` members, while a class has by default `private` members, and that deriving from a `struct` by default is `public`, and for a class `private`. Whatever you can do in a class, you can do in a struct, that means anything. – PaulMcKenzie Apr 23 '20 at 01:01
  • Yep i am aware of that too. I'm fairly new to C++ and wanted to do this conversion as a learning exercise as well. –  Apr 23 '20 at 01:03
  • 2
    Honestly, what can you learn from this? Again, a `struct` **is** a `class`. It's like turning a car into an automobile. Also, -- *to be better used with the program I am working on.* -- what do you mean by "better used with the program"? What would make the code "better" if the keyword `class` is used instead of `struct`? – PaulMcKenzie Apr 23 '20 at 01:04
  • @PaulMcKenzie I've just been using classes throughout my program and thought there may be some problems if I tried to call these structs from the other files in my program. I'm not sure sorry, I'm still learning so forgive my ignorance. –  Apr 23 '20 at 01:29
  • _create struct `abc_timer` within class `interval_timer`_ No, `interval_timer` is a _base class_ for `abc_timer`. The original code defines structs and local variables together, adding to the confusion. Start by moving the `abc_timer` and `counter_timer` structs out of `main`, but keep the declarations of `abc` and `counter` within main. – 1201ProgramAlarm Apr 23 '20 at 01:32
  • `class A : public B` -- if `B` is a `struct`, this is the same as `class A : B`. The only reason to choose between `struct` and `class` is preference, nothing more, nothing less. Some say to use `struct` for anything looking like `C`, and `class` for stuff that looks like `C++`. But that is all preference -- again, there is no difference between a `struct` and a `class`, except for the default access specifiers. A class can do anything a struct can do, and vice-versa. – PaulMcKenzie Apr 23 '20 at 03:41
  • @1201ProgramAlarm Heh. The structs and variables are declared together because they tried to be a 1:1 translation of lambdas into equivalent C++98 code. That was [stated requirement from the OP](https://stackoverflow.com/questions/61334533/c-boost-asynchronous-timer-to-run-in-parallel-with-program). I know, the mind boggles. I wouldn't write this in production, but hey. I'll refuse to restrict to decades old standards for almost any possible reason :) – sehe Apr 23 '20 at 15:00
  • @PaulMcKenzie I concur, however a class declared with `struct` makes its *own* list of bases public by default, not its children's. – Quentin Apr 23 '20 at 15:42

2 Answers2

1

struct abc_timer : interval_timer means that abc_timer inherits from interval_timer e.g. it gains all its members and methods. Converting this to classes would be class abc_timer : public interval_timer

Isaac Clancy
  • 409
  • 2
  • 7
0

Because io is a value that is passed to the Interval_Timer constructor, you can't use it as part of a default value for abc or counter. You'll need to use the member initializer list for the Interval_Timer coustructor.

Interval_Timer::Interval_Timer(boost::asio::io_service &io, millisec i)
    : interval(i), timer(io), abc(io, millisec(100)), counter(io, millisec(1000), abc)
{
    // ...
}

You definitions for abc and counter should be changed to just the variable name, and lose the parameters.

    // ...
    } abc;
    // ...
    } counter;

The default constructor for Interval_Timer should be removed, as the constructors for abc and counter needs to provide a value for io. Or you need to provide new constructors for those two classes so that they can be used in the default constructor without having to specify an io_service.

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56