Being graceful, this approach has a few drawbacks. As I wrote, this pattern is not very popular, and when a developer defines a derived class they may not know that the class must inherit from the Clonable.
There is also a hardly probable but still possible pitfall of copy-pasting an existing class. For example, we define OptionValueSInt64 by copying OptionValueUInt64. If we forget to rename the template argument, we will not have any compile-time errors:
class OptionValueSInt64 : public Cloneable<OptionValueUInt64, OptionValue> { ... };
Now our Clone function turn into:
std::shared_ptr<OptionValue> OptionValueSInt64 ::Clone() const override { return std::make_shared<OptionValueUInt64>(static_cast<const OptionValueUInt64&>(*this)); }
So, we get static_cast from OptionValueSInt64 to OptionValueUInt64 and undefined behaviour.
There's no need to include "Cloneable(), " here, it's implicit. (indeed you could remove the "OptionValue(), " here in a separate preliminary commit to make this patch's diff smaller/easier to read.