Why is this code compiling? (Question to C ++ template)

I am writing a generic container using a class template, with the restriction (policy) that the elements stored in the container must be derived from a specific base class.

Here is the class template definition

// GenericContainer.hpp
// --------------------------------------
class ContainerItem
{
protected:
    virtual ContainerItem& getInvalid() = 0;

public:
    virtual ~ContainerItem();
    bool isValid() const;
};


template<typename D, typename B>
class IsDerivedFrom
{
    static void Constraints(D* p)
    {
        B* pb = p; // this line only works if 'D' inherits 'B'
        pb = p; // suppress warnings about unused variables
    }

protected:
    void IsDerivedFrom2() { void(*p)(D*) = Constraints; }
};


// Force it to fail in the case where B is void
template<typename D>
class IsDerivedFrom<D, void>
{
    void IsDerivedFrom2() { char* p = (int*)0; /* error */ }
};



template <class T>
class GenericContainer : public IsDerivedFrom<T, ContainerItem>
{
private:
    typedef std::vector<T> TypeVect;
    void addElement(const T& elem);

    TypeVect m_elems;

public:
    unsigned int size() const;
    T& elementAt(const unsigned int pos);
    const T& elementAt(const unsigned int pos) const;
};


template <class T>
void GenericContainer<T>::addElement(const T& elem)
{
    m_elems.push_back(elem);
}

template <class T>
unsigned int GenericContainer<T>::size() const
{
    return m_elems.size();
}

template <class T>
T& GenericContainer<T>::elementAt(const unsigned int pos)
{
    unsigned int maxpos = m_elems.size();
    if (pos < maxpos)
        return m_elems[pos];
    return T::getInvalid();
}


template <class T>
const T& GenericContainer<T>::elementAt(const unsigned int pos) const
{
    unsigned int maxpos = m_elems.size();
    if (pos < maxpos)
        return m_elems[pos];
    return T::getInvalid();
}


// Class to be contained (PURPOSELY, does not derive from ContainerItem)
// Data.hpp
//----------------------------------------------------------------

class Data
{ /* implem details */};


// Container for Data items
// Dataset.h
// ----------------------------------------------------------------------------

#include "GenericContainer.hpp"
#include "Data.hpp"

class Dataset: public GenericContainer<Data>
{
public:
   Data& getInvalid();
};


// C++ source
// -----------------------------------------------------------
#include "Dataset.hpp"

Dataset ds;

Can someone explain why the code above compiles ?.

[change]

The above code should NOT compile for two reasons:

  • The Data class is NOT derived from the ContainerItem, and yet it can be stored in the GenericContainer (as shown in the dataset). By the way, this problem is now resolved thanks to the answer provided by Omifarious and jdv

  • "" , ABC ContainerItem, - , , ( ) , Data getInvalid() ContainerItem '. ?

BTW, : g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3

+3
2

IsDerivedFrom2 IsDerivedFrom, .

, , . , , , IsDerivedFrom. - . .

, , Boost, is_base_of Boost.

, GenericContainer , Boost:

#include <boost/static_assert.hpp>
#include <boost/type_traits/is_base_of.hpp>

template <class T>
class GenericContainer
{
private:
    typedef std::vector<T> TypeVect;
    void addElement(const T& elem);

    TypeVect m_elems;

public:
    unsigned int size() const;
    T& elementAt(const unsigned int pos);
    const T& elementAt(const unsigned int pos) const;

    GenericContainer() {
       BOOST_STATIC_ASSERT( (::boost::is_base_of<ContainerItem, T>::value) );
    }
};


template <class T>
void GenericContainer<T>::addElement(const T& elem)
{
    m_elems.push_back(elem);
}

template <class T>
unsigned int GenericContainer<T>::size() const
{
    return m_elems.size();
}

template <class T>
T& GenericContainer<T>::elementAt(const unsigned int pos)
{
    unsigned int maxpos = m_elems.size();
    if (pos < maxpos)
        return m_elems[pos];
    return T::getInvalid();
}


template <class T>
const T& GenericContainer<T>::elementAt(const unsigned int pos) const
{
    unsigned int maxpos = m_elems.size();
    if (pos < maxpos)
        return m_elems[pos];
    return T::getInvalid();
}
+2

Constraints , IsDerivedFrom2 . ++. , . boost .

+1

Source: https://habr.com/ru/post/1787105/


All Articles