Template-based opinion

I have this particular case and need some opinion on some aspects of the design.

Basically, I've already defined classes (which represent position in different spaces) and the classes don't have a specific relationship to each other.

So, I've developed a templated interpolator that can work with the current available position representing the classes.

About the same

template<typename TPoint>
class Interpolator
{
 .....

some function
{
TPoint::CalculateCriticalAxis(point);
}
}

      

As you can see, there are some static functions defined in all position classes that can be accessed inside the interpolator. So now, since someone who needs to use an interpolator and define a new class of position (points) will have to know that they need to define them by looking at the code, since there is no base class for positions. The question is, how can I create a base class that will also contain static methods that the user must override. As far as I understand, static methods cannot be overridden. So what's the simplest way to enforce them if someone wants to define a new position (point) class. I don't want to redo it as there are legacy position classes that are not from me and they are not related in some way. Thank!

+3


source to share


1 answer


Use a static member function defined as remote. The attribute [[deprecated( "message" )]]

allows you to print an error message when someone tries to access a missing implementation.

// May be, but doesn't need to be a template.
struct base_interface {
    // Likewise, this could be templated.
    [[deprecated( "Derived class must override calculation." )]]
    static value_type calculate_something() = delete;

    // "Public" interface, in the vein of the non-virtual idiom (NVI).
    // This must be a template, and it can't be a member - it a friend.
    template< typename derived >
    friend value_type something_of( derived const & o )
        { return o.calculate_something(); }
};

      


A known weakness of the duck seal is that the user may not try to access the missing implementation. This is a different problem. Any solution means access to all aspects of the proper derived class.

The base class can do this, but only carefully, because there are some problems:



  • The derived class will be incomplete in the definition of its base class. But it will be complete in the base class member function definitions.

  • The existence of a complete implementation of the derived class should be verified, but you don't actually want to instantiate all parts of the derived class template, much less associate it with a binary. "Too much" usage will bloat compile time and executable size, respectively.

One solution is the use of static_assert

and decltype

inside the base class constructor CRTP.

// CRTP template, derived class must pass itself to base.
template< class derived >
class base_interface {
    base_interface() {
        static_assert ( std::is_same< decltype( derived::calculate_something() ),
                                      typename derived::value_type >::value,
            "derived class is missing calculate_something" );
    }

    // Just enough to allow the static_assert condition to evaluate as false.
    static struct invalid calculate_something();
    typedef void value_type;
};

      

http://coliru.stacked-crooked.com/a/b2c5f9bf8ed58a09

Please note that this is a completely different solution from the first. This prevents the default CRTP database from being created by default, but it is a small price to pay. Alternatively, you can put static_assert

in another function that will definitely be available and keep the trivial default constructor.

0


source







All Articles