"Pimp my Library" in C++

Viewed 391

In Scala, there's a design pattern often called "pimp my library". The basic idea is that we have some class Foo (presumably in some library that we can't modify), and we want Foo to act like it has some method or behavior frobnicate, we can use an implicit class to add the method after the fact.

implicit class Bar(val foo: Foo) extends AnyVal {
  def frobnicate(): Unit = {
    // Something really cool happens here ...
  }
}

Then, if we have an instance of Foo, we can call frobnicate on it and, as long as Bar is in scope, the Scala compiler will be smart enough to implicitly cast Foo to Bar.

val foo = new Foo()
foo.frobnicate() // Correctly calls new Bar(foo).frobnicate()

I'd like to do this same sort of thing in C++. I know that C++ has implicit casts, but they don't seem to trigger when accessing members. For a concrete example, the following code in C++ produces an error.

class Foo {}; // Assume we can't modify this class Foo

class Bar {
private:
  Foo foo;
public:
  Bar(Foo foo) : foo(foo) {}
  void frobnicate() {
    cout << "Frobnicating :)" << endl;
  }
};

void frobnicate(Bar bar) {
  cout << "Frobnicating :)" << endl;
}

int main() {
  Foo value;
  frobnicate(value);  // This works
  value.frobnicate(); // But this doesn't
  return 0;
}

On the value.frobnicate() line, C++ doesn't seem to look for implicit conversions in that context.

main.cc:30:9: error: ‘class Foo’ has no member named ‘frobnicate’

Note: I'm compiling with C++11 right now. At a cursory glance at the newer C++ versions, it doesn't seem like anything that would affect this question has changed since then. C++11-compatible solutions are ideal, but a way to do this in newer C++ versions would be good as well, for didactic purposes.

4 Answers

Not exactly, but...

#include <iostream>

class Foo
{
public:
    void nothingUpMySleeve()
    {
        std::cout << "Foo!\n";
    }
};

class Bar
{
private:
    Foo & foo;

public:
    Bar(Foo & foo) : foo { foo }
    {
    }

    void frobnicate()
    {
        std::cout << "Frobnicating\n";
    }

    Foo * operator ->()
    {
        return &this->foo;
    }

    operator Foo &()
    {
        return this->foo;
    }
};

void thisFunctionOnlyAcceptsFoo(Foo & foo)
{
    std::cout << "Yes, that's a Foo\n";
}

void useExtendedType(Bar wrapper)
{
    // Use the extension function
    wrapper.frobnicate();

    // Use arrow notation to use the original functions
    wrapper->nothingUpMySleeve();

    // Implicit conversion kicks in when necessary
    thisFunctionOnlyAcceptsFoo(wrapper);
}

int main()
{
    Foo value;

    // Pass to a function that uses Bar
    useExtendedType(value);
}

I really don't recommend doing this in actual code though. It's just a cheap party trick.

It's not even clear whether Bar should own a copy of Foo or just reference it. I opted for just referencing because I'm presuming some other code is managing the lifetime of Foo, and this way Bar can be created and destroyed incredibly cheaply. You just have to be careful that Bar's lifetime is always shorter than Foo's, otherwise it's nasal demons I'm afraid.

Related