Inheritance and nested class - c++

I'm trying to implement different versions of a data structure. Suppose it has an interface shown below (it's simplified):
template <typename T>
class Base {
public:
class Iterator {
virtual auto operator*() -> T& = 0;
};
public:
virtual auto Find(const T& value) -> Iterator = 0;
}
Now I want to inherit a class that will implement it:
template <typename T>
class Derived : public Base<T> {
public:
class Iterator {
auto operator*() -> T& override {
/* ... */
}
};
public:
auto Find(const T& value) -> Iterator override {
/* ... */
};
}
Problem is that I need to implement Iterator based on what Derived does, but Find function's signature brakes because of Derived::Iterator (it should be Base::Iterator). Is there a way to do so or do I have to give up on using interface class?

From what I understand, what you are trying to achieve is related to type erasure or maybe static polymorphism. You want Base::Iterator to be a non-abstract generalized type, that can be constructed from any Derived implementation.
This is a dynamic solution that you can optimize based on your needs
template<typename T>
struct Base
{
// This is the interface that needs to be implemented by the derrived classe's iterator
struct IIterator
{
virtual T& Get() = 0;
};
// this is the generalized type that needs to be returned by find()
struct Iterator
{
Iterator(std::unique_ptr<IIterator> impl ):
_impl(std::move(impl))
{
}
T& operator*() { _impl->Get(); }
private:
// You can implement small struct optimization by making a byte array big enough
// to store any of the implementations and avoid dynamic memory
std::unique_ptr<IIterator> _impl;
};
virtual Iterator find() = 0;
};
template<typename T>
struct Derived : public Base<T>
{
// Now in derived we implement our iterator
struct IteratorImpl : Base<T>::IIterator
{
IteratorImpl(T* p) : ptr(p) {}
T& Get() override { return *ptr; }
T* ptr;
};
typename Base<T>::Iterator find() override
{
IteratorImpl result(nullptr);
// After finding we need to construct the generalized type from the implementation
return typename Base<T>::Iterator(std::make_unique<IteratorImpl>( result ));
}
};
Another way to do something like that is by using templates and CRTP to make a static interface. CRTP is a technique that involves passing the derived type information back to the base class using it's template arguments and using that information to define or find an implementation for the Base iterator based on the derived type.

Related

Force static method in class based on interface in C++

I am making a vector-class which has the option to take an allocator as a template parameter. To ensure a user-defined allocator works with the vector, I provide an interface which sets the minimum requirements for a given allocator. Since the allocator is just used to allocate and deallocate, it has no member variables, and all methods are static. Is there a way to make sure any implementation has a given set of methods that are also static? I know you cannot have a method be static and virtual at the same time, but I essentially want any allocator derived from base_allocator to have a set of methods, and for those methods to be static. In short: Can you work around the virtual static contradiction in c++?
This is my current code:
// in namespace mem_core
// Interface for usage of custom allocators with the custom:: namespace containers.
template <typename T>
class base_allocator {
public:
using T_ptr = T*;
using T_ref = T&;
virtual T_ptr address(const T_ref value);
// memory methods should allocate for amount elements of type T
virtual void deallocate(T_ptr const ptr, const size_t& count) = 0;
virtual T_ptr allocate(const size_t& amount) = 0;
};
_MEMORY_CORE_END_ // namespace mem_core }
#undef _MEMORY_CORE_BEGIN_
#undef _MEMORY_CORE_END_
// default allocator CLASS TEMPLATE
template <typename T>
class allocator : public mem_core::base_allocator<T> {
public:
using value_type = T;
using T_ptr = T*;
using T_ref = T&;
static T_ptr address(T_ref value) noexcept {
return mem_core::addressof<T>(value);
}
static void deallocate(T_ptr const ptr, const size_t& count) {
mem_core::deallocate<T>(ptr, count);
}
static T_ptr allocate(const size_t& amount) {
return mem_core::allocate<T>(amount);
}
};
This of course works, but there is no guarantee that a user-defined allocator has made the virtual methods static, as that is a requirement for the allocator to work within the vector-class.
e.g. like this:
template <typename T, typename alloc_type = allocator<T>>
class vector {
public:
using iterator = vector_iterator<vector<T, alloc_type>>;
using T_ptr = T*;
using T_ref = T&;
using value_type = T;
private:
T_ptr m_data;
size_t m_size;
size_t m_capacity;
public:
vector() : m_data(nullptr), m_size(0), m_capacity(0) noexcept {};
vector(const size_t& initial_cap) : m_size(0) {
m_data = alloc_type::allocate(m_capacity); // Requires static allocate method
m_capacity = initial_cap;
}
// rest of vector class ...
It's possible to require a class with certain methods defined as static using SFINAE. The following example uses C++20's concepts, but with a little bit of work can be adapted to use pure SFINAE, since that's the only thing that's required here. This example defines a concept has_static_methods that requires a class to implement both "function" and "function2" as static methods. Non-static methods, virtual or not, fail:
#include <iostream>
#include <type_traits>
template<typename T> struct is_function : public std::false_type {};
template<typename Ret, typename ...Args>
struct is_function<Ret (*)(Args...)> : public std::true_type {};
struct not_static {
void function();
static void function2();
};
struct is_static {
static void function();
static void function2();
};
template<typename T>
concept has_static_methods = is_function<decltype(&T::function)>::value &&
is_function<decltype(&T::function2)>::value;
// Ok's template parameter type must implement both static methods.
template<has_static_methods T> void ok()
{
}
int main()
{
ok<is_static>(); // OK
ok<not_static>(); // Error, unsatisfied contsraint.
return 0;
}
And with a little bit of extra work it's possible to enforce static methods with specific signatures.
Now, keep in mind that this doesn't really prevent anyone from defining a subclass with non-static methods. This requires any class that gets passed as a parameter to your template to meet this constraint.

Factory method combining static and dynamic polymorphism

I am working with two corresponding class hierarchies, A and B, where I need to create instances of sub-types of B from instances of matching sub-types of A. I can't find a "clean" way to create B objects from A objects because
B objects only have pointers to A objects so a B::factory would not know what kind of B to make as it doesn't know what derived type of A it gets without some sort of ugly dynamic_cast that would be hard to maintain as new sub-types of A and B are added to the library.
B classes depend on template parameters that A classes do not. It's not obvious how a factory method in A could therefore create a B since A classes have virtual inheritance and such a method would need to be templated, which is not possible.
Example classes:
template<typename T>
struct AType {
virtual void apply( const T*, T* ) const = 0;
};
template<typename T>
struct ASubType1 : public AType<T> {
void apply( const T*, T* ) const override;
};
template<typename T>
struct ASubType2 : public AType<T> {
void apply( const T*, T* ) const override;
};
template<typename T, typename U>
class BType {
public:
BType( const AType<T>* A_in ) : A(A_in) {}
virtual std::common_type_t<T,U> compute( const U& ) = 0;
static std::unique<BType> factory( const AType<T>* A_in );
// if A_in has type ASubType1, return std::make_unique<BSubType1<T,U>>
// else if A_in has type ASubType2, return std::make_unique<BSubType2<T,U>>
// else return nullptr
protected:
auto get_A() const { return A; } // So BSubTypes have access
private:
AType<T>* A;
};
template<typename T, typename U>
class BSubType1 : public BType<T,U> {
public:
using BType<T,U>::BType;
std::common_type_t<T,U> compute( const U& ) override;
};
template<typename T, typename U>
class BSubType2 : public BType<T,U> {
public:
using BType<T,U>::BType;
std::common_type_t<T,U> compute( const U& ) override;
};
It seems like there ought to be some sort of clever Vistor-based solution to generating the correct B objects from their corresponding A, however, the only solution besides dynamic_cast
that I have found is to add a method to the A classes that can return an enum corresponding to each A sub-type and have B::factory take this enum as an argument to return the correct sub-type of B. This approach is not particularly satisfying as it requires intrusively changing type information in a base class, where it would be desirable to add new classes to the A and B families without having to touch any existing classes.
Is there a more elegant approach, such as one using visitors, than what I am currently doing?

how to cleanly dispatch virtual calls from non templated parent to templated child

I have a really ugly implementation of something that I want to refactor but I am not sure how. Here is what I have:
Some templated object
template< typename T>
class Thing { };
An interface
class IService {
public:
virtual void func(void* arg) = 0;
};
A templated class implementing it
template< typename T>
class Service< T> : public IService {
virtual void func(void* arg) {
func((Thing< T>* )arg);
}
void func(Thing< T>* arg) {
// do something with arg
}
};
The reason is that I want a non-templated IService that I can pass around. templating IService will cause massive refactor through a large code base.
So instead, I instantiate Service< T> objects, pass around the IService, and call func with templated Thing objects, which does an ugly cast to a similar function that takes the actual Thing object. Is there any clean way to achieve this without templating IService?
Edit: some more context. This is what I really want:
template<typename T>
class IService {
public:
virtual void func(Thing<T>* arg) = 0;
};
However, I cannot template IService.
Assuming that you don't want to or can't give Thing a base class, and given that a given Service<T> can only handle Things which have the same T, you could do this:
class IService {
public:
template <typename T>
void func(Thing<T>* arg) {
auto self = dynamic_cast<Service<T>*>(this);
if (self) {
self->func(arg);
} else {
// decide how to handle this error
}
}
};
func would not be virtual. It is just a template policy that deriving from IService needs to have a func(Thing<T>*) method.
Maybe some interface for the Thing would do the trick?
class IThing { };
template< typename T>
class Thing: public IThing { };
class IService {
public:
virtual void func(IThing* arg) = 0;
};
template< typename T>
class Service: public IService {
virtual void func(IThing* arg) {
Thing<T> *thing = dynamic_cast<Thing<T> *>(arg);
if (thing) {
// implementation
}
}
};
I'm assuming you want to type-erase Thing's <T> template parameter through the use of a non-templated IService class and that you do not care about T in the implementation of IService. I am not sure these assumption are correct, but here's a possible solution.
I'm also assuming that having virtual dispatch inside Thing suffice in your use case.
// Create a `ThingBase` class to "type-erase" `Thing`'s
// template parameter. `ThingBase` should contain your
// `func`, as `virtual`.
struct ThingBase
{
virtual void func();
};
// Your `Thing<T>` class should override `func`
template <typename T>
struct Thing : ThingBase
{
void func() override { /* ... */ }
};
// Your `IService` now only needs to be as follows:
struct IService
{
void func(ThingBase& x)
{
x.func();
}
};

C++ class template specialization with pointers

I have a tree structure of the following format:
template <typename DataType>
class Tree {
DataType *accessData() { return data; }
Tree *child1, *child2;
DataType *data;
};
template <typename DataType>
class Root : public Tree<DataType> {
// root provides storage of nodes; when it goes out of scope, the
// entire tree becomes invalid
MemoryPool<Tree> nodeStorage;
MemoryPool<DataType> dataStorage;
};
I use a variety of instantiations of this template in my program. It works quite well.
One instantiation, however, uses a DataType which is just an enum (so it's the same size as a pointer!) and because speed is essential (both when the tree is built, and when it is accessed), I'd much rather have this instantiation use the enum directly instead of a pointer. An example how I'd like the code to look (not strict):
Tree<BigClass> *foo = ...;
foo->accessData()->doBigClassThings();
Tree<int> *bar = ...;
int x = 4 + bar->accessInt();
Now of course I could just keep the current templates but I don't like this extra pointer access and especially the need to allocate ints in the root. Any ideas on how I can specialize the template to provide this functionality, or other approaches?
I've tried to specialize the template like this (and a bazillion other ways)
template <> Tree<int> { ... }
But I just keep getting compile errors. Any help would be greatly appreciated!
I would recommend using a traits class to deduce the type of object stored in Tree.
// The default traits.
template <typename DataType> struct TreeDataType
{
using Type = DataType*;
};
template <typename DataType>
class Tree {
// Define the data type using the traits class.
using Data = typename TreeDataType<DataType>::Type;
Data accessData() { return data; }
Tree *child1, *child2;
Data data;
};
and then specialize TreeDataType for MyEnum.
template <> struct TreeDataType<MyEnum>
{
using Type = MyEnum;
};
I suggest defining multiple data classes with the same interface that you can use as DataType template parameters. Abstract the way the data is stored from the way the data is accessed.
template<typename T>
class value_data
{
private:
T _value;
public:
T& access() { return _value; }
const T& access() const { return _value; }
};
template<typename T>
class unique_ptr_data
{
private:
std::unique_ptr<T> _value;
public:
T& access() { assert(_value != nullptr); return *_value; }
const T& access() const { assert(_value != nullptr); return *_value; }
};
enum class my_enum { /* ... */ };
class my_enum_data
{
private:
my_enum _value;
public:
my_enum& access() { return _value; }
const my_enum& access() const { return _value; }
};
Then, in your Tree class, you can use them through their common interface:
template <typename DataType>
class Tree {
auto& accessData() { return data.access(); }
Tree *child1, *child2;
DataType data;
};

C++ mixing strongly typed base class with CRTP and return value type deduction

I have some conceptual problem in a class hierarchy, where the Base class depends on a fixed scalar type T, but the derived CRTP'ed classes use return value type deduction.
For example, consider the following class hierarchy:
template<typename ... Args> struct VectorBase;
template<typename T>
struct VectorBase<T>
{
virtual T eval(int) const = 0;
auto operator[](int i) {return this->eval(i);}
};
template<typename T, typename Derived>
struct VectorBase<T, Derived> : public VectorBase<T>
{
virtual T eval(int i) const override final { return this->operator[](i); }
auto operator[](int i) const
{
return static_cast<Derived const&>(*this).operator[](i);
}
};
template<typename T>
struct Vector : public VectorBase<T, Vector<T> >
{
//just for code shortness,
//in reality there is a container which returns the corresponding elements
auto operator[](int i) const { return T{}; }
};
template<typename VectorType>
struct SomeTransformation : public VectorBase< /* ... what to write here generically? */ double, SomeTransformation<VectorType> >
{
VectorType const& v;
SomeTransformation(VectorType const& _v) : v(_v) {}
auto operator[](int i) const
{
//do something with vector v and return i-th element, e.g.
return v[i]*0.1;
}
};
DEMO
Now, given a specific vector with value type int, say, one can apply SomeTransformation and get a vector of value type double. Moreover, I can be sure that SomeTransformation derives from VectorBase<double>, so that, for example, I can't falsely assign it to a VectorBase<int>-pointer:
int main()
{
Vector<int> v;
std::cout<<typeid(decltype(v[0])).name()<<std::endl; //prints "i" for int
auto u = SomeTransformation<decltype(v)>(v);
std::cout<<typeid(decltype(u[0])).name()<<std::endl; //prints "d" for double
//works
std::unique_ptr<VectorBase<double> > ud = std::make_unique<SomeTransformation<decltype(v)> >(v);
//gives a compile-time error, which is good
//std::unique_ptr<VectorBase<int> > ui = std::make_unique<SomeTransformation<decltype(v)> >(v);
}
Now for the problem: in the scalar type argument of SomeTransformation, where I wrote /* ... what to write here generically? */, I really would want to write something like
template<typename VectorType>
struct SomeTransformation :
public VectorBase<decltype(std::declval<SomeTransformation<VectorType> >().operator[](0)), SomeTransformation<VectorType> >
{
//...
};
in order to deduce the value type of the transformation automatically and propagate this type down to the base class. However, this doesn't seem to work, which I think is because the base classes are instantiated before the derived class ... so the class of which I want to deduce the type doesn't exists yet.
Is there any way to obtain this behaviour without breaking the inheritance hierarchy?
I figured out a possible alternative by myself and want to bring it up for discussion.
One could for instance add a type parameter T also to the derived class and then use a dummy type in order to instantiate this class once. With this, it is possible to deduce the return type of the so-created class, which is used in a next step to instantiate the class to be really used.
Example:
namespace detail
{
template<typename T, typename VectorType>
struct SomeTransformation :
public VectorBase<T, SomeTransformation<T, VectorType> >
{
//the same as above
};
}
struct DummyType
{
//make any type convertible to DummyType
template<typename T> DummyType(T const&) {}
};
template<typename VectorType>
using SomeTransformationValueType =
decltype(std::declval<detail::SomeTransformation<DummyType, VectorType> >().operator[](0));
template<typename VectorType>
using SomeTransformation =
typename detail::SomeTransformation<SomeTransformationValueType<VectorType>, VectorType>;
DEMO