Search code examples
c++templatesinheritancetype-traitsenable-if

How to enable a inheritance switch depending on a template type


I want to implement a Implementation switch depending on the template parameter I pass to a class:

  • If the passed template type is derived from a specific class (here: Serializable) then the container DataElement which creates an instance of the type should derive from SerializableElement and overload the two pure virtual methods inherited from it (here: unloadTo and loadFrom).
  • Whereas, if the passed template type is not derived from Serializable DataElement should not derive from SerializableElement and therefore should not overload the pure virtual methods.

I adapted my code to be able to hide away class methods inside the class DataElement, by a trick mentioned from here C++: Enable method based on boolean template parameter

I do get following error though, while adapting the trick to my problem:

error: cannot declare variable ‘dataEle’ to be of abstract type ‘DataElement’


testEnableIF.h

#ifndef TESTENABLEIF_H_
#define TESTENABLEIF_H_


#include <iostream>
#include <type_traits>

/// @brief  some dummy class to mark a type as Serializable
class Serializable {};

/// @brief abstract base class which adds additional abilities to DataElement
class SerializableElement {
public:
    virtual void unloadTo(int x) =0;
    virtual void loadFrom(int x) =0;
};
/// @brief  used by the DataElement class
class DisableSerializability {};

/// @brief  is a container class which manages the creation and
///         access to a data element of type _DataType
    template< typename _DataType, bool _IsDataSerializable = std::is_base_of<Serializable,_DataType>::value >
    class DataElement :
        //  derive from SerializableElement, only if the template type _DataType is derived from the interface Serializable
        public
        std::conditional<
            _IsDataSerializable,
            SerializableElement,    // add additional properties to DataElement if its Serializable
            DisableSerializability >::type {
    public:
        DataElement(): m_content(new _DataType()){}

        void foo(int x) { std::cout << "in foo" << std::endl; }

        template <bool _EnabledAbility = _IsDataSerializable>
        void unloadTo(typename std::enable_if<_EnabledAbility, int>::type x)
        { std::cout << "in unloadTo" << std::endl; }

        template <bool _EnabledAbility = _IsDataSerializable>
        void loadFrom(typename std::enable_if<_EnabledAbility, int>::type x)
        { std::cout << "in loadFrom" << std::endl; }

    private:
        _DataType* m_content;
    };


    #endif /* TESTENABLEIF_H_ */

test code which calls class DataElement

main.cpp

#include "testEnableIF.h"

class SerializableType : public Serializable {
    int x;
    int y;
    int z;
};
class NonSerializableType {
    int u;
};

int main() {
    SerializableType sType;
    NonSerializableType nType;  // other type without being derived from Serializables

    DataElement<SerializableType> dataEle;
    dataEle.unloadTo(3);

    return 0;
}

Solution

  • template <bool _EnabledAbility = _IsDataSerializable>
    void unloadTo(typename std::enable_if<_EnabledAbility, int>::type x);
    

    is not an override of

    virtual void unloadTo(int x) = 0;
    

    You would even get the error by adding override.

    The way to fix would be to inherit from a concrete class which inherits from SerializableElement instead of inherit only from interface.

    Demo