Right, but speaking_animal(x) is not dynamic OOP dispatch; it's a template function that gets instantiated for each animal type.
Moreover, everything here can be done without a concept.
This version of the code builds with g++ -std=c++17. We just get worse diagnostics if we try to use something as a Speaker which doesn't conform.
#include <iostream>
using namespace std;
class Duck {
public:
void speak() const {
cout << "quack";
}
};
class Dog {
public:
void speak() const {
cout << "auau";
}
};
class Cat {
public:
void speak() const {
cout << "miau";
}
};
template<typename T>
void speaking_animal(const T& animal) {
animal.speak();
cout << "\n\n";
}
template<typename... T>
void speaking_farm(const T&... animals) {
auto space_adder = [&](auto creature) -> void {
creature.speak();
cout << " ";
};
(space_adder(animals), ...);
}
int main() {
Duck duck;
Dog dog;
Cat cat;
speaking_animal(duck);
speaking_animal(dog);
speaking_animal(cat);
speaking_farm(duck, dog, cat);
}
I was thinking about more something along these lines. But note the double indirection: we end up passing the smart pointer
animal_pointer by reference.
We achieve the "signature thing" though in that we take these animal objects and effectively get them to to conform to the common animal_pointer abstract base without their cooperation.
#include <iostream>
using namespace std;
class Duck {
public:
void speak() const { cout << "quack"; }
};
class Dog {
public:
void speak() const { cout << "auau"; }
};
class Cat {
public:
void speak() const { cout << "miau"; }
};
class animal_pointer {
public:
virtual void speak() const = 0;
};
template <typename T> class animal_pointer_impl : public animal_pointer {
private:
T *obj;
public:
animal_pointer_impl(T *o) : obj(o) { }
virtual void speak() const { obj->speak(); }
};
void animal_api(const animal_pointer &p)
{
p.speak();
cout << '\n';
}
int main() {
Duck duck;
Dog dog;
Cat cat;
animal_pointer_impl<Duck> p0(&duck);
animal_pointer_impl<Dog> p1(&dog);
animal_pointer_impl<Cat> p2(&cat);
animal_api(p0);
animal_api(p1);
animal_api(p2);
}
animal_api is a regular function, which represents some external API that we don't get to recompile.