I like NVI idiom.
But sometimes I want to reduce vftable cost from NVI idiom. Then I tried to apply CRTP to NVI as following.
template<typename E>
class unary_interface {
public:
virtual ~unary_interface() = default;
public:
double operator()(const double x) const
{
return static_cast<const E&>(*this).apply(x); //occurs compile error!!!
}
};
class square : public unary_interface<square> {
private:
double apply(const double x) const
{
return x * x;
}
};
But this code occurs compile error.
If I change apply function in private field to public, encapsulation is broken. I got an idea that opaque alias solve this problem as following.
template<typename E>
class unary_interface {
public:
virtual ~unary_interface() = default;
protected:
class input_type {
public:
explicit input_type(const double x) : _x(x) {}
operator double() const
{
return _x;
}
private:
const double _x;
};
public:
double operator()(const double x) const
{
return static_cast<const E&>(*this).apply(input_type(x));
}
};
class square : public unary_interface<square> {
using base_type = unary_interface<square>;
public:
double apply(const base_type::input_type& d) const
{
const double x = static_cast<const double>(d);
return x * x;
}
};
This design keeps to disable to access apply function except from operator() of unary_interface.
At first glance "apply function" is exposed to user code, but apply function is accept only protected opaque alias type that is defined on unary_interface in protected field. I think that this combination is very good and reduce virtual function cost with keeping strong encapsulation.
Does this idea has any defect that I can not find out, and do you have a specific name for this design?