Question

I would like to obey Law of Demeter. But I would also like to lazy load some objects passed to constructors. How should I implement that? Pass a wrapper class? Pass a function pointer?

Was it helpful?

Solution

You can actually write a generic wrapper that accomplish this:

template <typename T>
class Lazy {
public:
  explicit Lazy(T const& t): _loader(), _item(t) {}
  explicit Lazy(T&& t): _loader() _item(t) {}
  explicit Lazy(std::function<T()> l): _loader(l), _item() {}

  T& operator*() { return this->get(); }
  T const& operator*() const { return this->get(); }

  T* operator->() { return &this->get(); }
  T const* operator->() const { return &this->get(); }

private:
  T& get() { if (not _item) { _item = _loader(); } return *_item; }
  T const& get() const { if (not _item) { _item = _loader(); } return *_item; }

  std::function<T()> _loader;
  mutable boost::optional<T> _item;
}; // class Lazy

This class guarantees that the loader is executed once, as long as it completes. If it does not complete, then execution will be retried on the next access. It is not thread-safe.

Usage:

// Output prime numbers as text
bool isPrime(int);
std::string toEnglish(int);

void print(int i, Lazy<std::string> const& heavy) {
    if (not isPrime(i)) { return; }

    std::cout << *heavy << "\n";
}

int main(int argc, char* argv[]) {
    if (argc < 2) { return 1; }

    int max = atoi(argv[1]);
    for (int i = 2; i <= max; ++i) {
        print(i, [=](){ return toEnglish(i); });
              // ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++11 lambda syntax
    }
}

Here, toEnglish is only ever invoked for prime numbers.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top