Force static method in class based on interface in C++ - 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.

Related

Inheritance and nested class

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.

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 specialize a non-templated-member function of a template class for multiple types?

I'm biting of my nails on the syntax required to partially specialize a member function for multiple types. Here is what I have:
#include <cstdint>
#include <string>
class Property
{
public:
virtual int read(uint8_t *) = 0;
};
template<typename T>
class PropertyValue
{
T value_;
public:
int read(uint8_t *);
};
// specialized for std::string
template<>
int PropertyValue<std::string>::read(uint8_t *buf) { /* put string-value to buf */}
Now I would want to specialize the read-function for different enum-types. I tried a combination of enable_if and is_same which looks promissing, then putting it inside the template-declaration (compiler told me there are now 2 template arguments whereas 1 was expected).
Putting it inside the class-definition was not working either. Outside ... well, here's what I currently have.
// specialize for some enums
template<typename T>
typename std::enable_if<std::is_same<T, enum Enum1>::value ||
std::is_same<T, enum Enum2>::value, int>::type
PropertyValue<T>::read(uint8_t *buf)
{
return encode_enum(buf, value_);
}
Where is my thinking wrong?
EDIT: Writing it like this compiles and works:
template<>
int PropertyValue<Enum 1>::read(uint8_t *buf)
{
return encode_enum(buf, value_);
}
template<>
int PropertyValue<Enum 2>::read(uint8_t *buf)
{
return encode_enum(buf, value_);
}
PropertyValue::value itself is not a template. It's not a template class, it's not a template function. It's a member of a template class, which is not the same thing as being a template itself.
You have to specialize the entire class.
template<>
class PropertyValue<std::string>
{
std::string value_;
public:
int read(uint8_t *)
{
// Your specialization goes here.
}
};
Even if read() itself was a template, you must still specialize its class, before you can specialize a template class's template member.
Of course, if your template class has many other members and methods, every one of them have to be specialized here, leading to plenty of code getting duplicated. At that point, you will be faced with several options for refactoring out that duplicated code. The best approach for that depends on the particular details.
But that's how it's done...
EDIT: one common approach is to use a helper template class:
template<typename T> class PropertyValue; // Forward declaration
template<typename T> class do_read {
public:
static int do_it( PropertyValue<T> &me, uint8_t *p )
{
// your default implementation
}
};
template<> class do_read<std::string> {
public:
static int do_it( PropertyValue<std::string> &me, uint8_t *p )
{
// your specialization
}
};
template<typename T>
class PropertyValue
{
T value_;
public:
int read(uint8_t *p)
{
return do_read<T>::do_it(*this, p);
}
};

Property system based on std::any: template type deduction

To implement a property system for polymorphic objects, I first declared the following structure:
enum class access_rights_t
{
NONE = 0,
READ = 1 << 0,
WRITE = 1 << 1,
READ_WRITE = READ | WRITE
};
struct property_format
{
type_index type;
string name;
access_rights_t access_rights;
};
So a property is defined with a type, a name and access rights (read-only, write-only or read-write). Then I started the property class as follows:
template<typename Base>
class property : property_format
{
public:
template<typename Derived, typename T>
using get_t = function<T(const Derived&)>;
template<typename Derived, typename T>
using set_t = function<void(Derived&, const T&)>;
private:
get_t<Base, any> get_f;
set_t<Base, any> set_f;
The property is associated to a base type, but may (and will) be filled with accessors associated to an instance of a derived type. The accessors will be encapsulated with functions accessing std::any objects on an instance of type Base. The get and set methods are declared as follows (type checking are not shown here to make the code minimal):
public:
template<typename T>
T get(const Base& b) const
{
return any_cast<T>(this->get_f(b));
}
template<typename T>
void set(Base& b, const T& value_)
{
this->set_f(b, any(value_));
}
Then the constructors (access rights are set to NONE to make the code minimal):
template<typename Derived, typename T>
property(
const string& name_,
get_t<Derived, T> get_,
set_t<Derived, T> set_ = nullptr
):
property_format{
typeid(T),
name_,
access_rights_t::NONE
},
get_f{caller<Derived, T>{get_}},
set_f{caller<Derived, T>{set_}}
{
}
template<typename Derived, typename T>
property(
const string& name_,
set_t<Derived, T> set_
):
property{
name_,
nullptr,
set_
}
{
}
The functions passed as arguments are encapsulated through the helper structure caller:
private:
template<typename Derived, typename T>
struct caller
{
get_t<Derived, T> get_f;
set_t<Derived, T> set_f;
caller(get_t<Derived, T> get_):
get_f{get_}
{
}
caller(set_t<Derived, T> set_):
set_f{set_}
{
}
any operator()(const Base& object_)
{
return any{
this->get_f(
static_cast<const Derived&>(object_)
)
};
}
void operator()(Base& object_, const any& value_)
{
this->set_f(
static_cast<Derived&>(object_),
any_cast<Value>(value_)
);
}
};
Now, considering these dummy classes.
struct foo
{
};
struct bar : foo
{
int i, j;
bar(int i_, int j_):
i{i_},
j{j_}
{
}
int get_i() const {return i;}
void set_i(const int& i_) { this->i = i_; }
};
I can write the following code:
int main()
{
// declare accessors through bar methods
property<foo>::get_t<bar, int> get_i = &bar::get_i;
property<foo>::set_t<bar, int> set_i = &bar::set_i;
// declare a read-write property
property<foo> p_i{"bar_i", get_i, set_i};
// declare a getter through a lambda
property<foo>::get_t<bar, int> get_j = [](const bar& b_){ return b_.j; };
// declare a read-only property
property<foo> p_j{"bar_j", get_j};
// dummy usage
bar b{42, 24};
foo& f = b;
cout << p_i.get<int>(f) << " " << p_j.get<int>(f) << endl;
p_i.set<int>(f, 43);
cout << p_i.get<int>(f) << endl;
}
My problem is that template type deduction doesn't allow me to declare a property directly passing the accessors as arguments, as in:
property<foo> p_i{"bar_i", &bar::get_i, &bar::set_i};
Which produces the following error:
prog.cc:62:5: note: template argument deduction/substitution failed:
prog.cc:149:50: note: mismatched types std::function<void(Type&, const Value&)> and int (bar::*)() const
property<foo> p_i{"bar_i", &bar::get_i, set_i};
Is there a way to address this problem while keeping the code "simple"?
A complete live example is available here.
std::function is a type erasure type. Type erasure types are not suitable for deduction.
template<typename Derived, typename T>
using get_t = function<T(const Derived&)>;
get_t is an alias to a type erasure type. Ditto.
Create traits classes:
template<class T>
struct gettor_traits : std::false_type {};
this will tell you if T is a valid gettor, and if so what its input and output types are. Similarly for settor_traits.
So
template<class T, class Derived>
struct gettor_traits< std::function<T(Derived const&)> >:
std::true_type
{
using return_type = T;
using argument_type = Derived;
};
template<class T, class Derived>
struct gettor_traits< T(Derived::*)() >:
std::true_type
{
using return_type = T;
using argument_type = Derived;
};
etc.
Now we got back to the property ctor:
template<class Gettor,
std::enable_if_t< gettor_traits<Gettor>{}, int> =0,
class T = typename gettor_traits<Gettor>::return_value,
class Derived = typename gettor_traits<Gettor>::argument_type
>
property(
const string& name_,
Gettor get_
):
property_format{
typeid(T),
name_,
access_rights_t::NONE
},
get_f{caller<Derived, T>{get_}},
nullptr
{
}
where we use SFINAE to ensure that our Gettor passes muster, and the traits class to extract the types we care about.
There is going to be lots of work here. But it is write-once work.
My preferred syntax in these cases would be:
std::cout << (f->*p_i)();
and
(f->*p_i)(7);
where the property acts like a member function pointer, or even
(f->*p_i) = 7;
std::cout << (f->*p_i);
where the property transparently acts like a member variable pointer.
In both cases, through overload of ->*, and in the second case via returning a pseudo-reference from ->*.
At the end of this answer is a slightly different approach. I will begin with the general problem though.
The problem is &bar::get_i is a function pointer to a member function while your alias is creating a function object which needs the class as additional template parameter.
Some examples:
Non member function:
#include <functional>
void a(int i) {};
void f(std::function<void(int)> func)
{
}
int main()
{
f(&a);
return 0;
}
This works fine. Now if I change a into a struct:
#include <functional>
struct A
{
void a(int i) {};
};
void f(std::function<void(int)> func)
{
}
int main()
{
f(std::function<void(int)>(&A::a));
return 0;
}
this gets the error:
error: no matching function for call to std::function<void(int)>::function(void (A::*)(int))'
because the std::function object also need the base class (as you do with your alias declaration)
You need a std::function<void(A,int)>
You cannot make your example much better though.
A way to make it a "bit" more easier than your example would maybe be this approach using CRTP.
#include <functional>
template <typename Class>
struct funcPtr
{
template <typename type>
using fun = std::function<void(Class,type)>;
};
struct A : public funcPtr<A>
{
void a(int i) {};
};
void f(A::fun<int> func)
{
};
int main()
{
f(A::fun<int>(&A::a));
return 0;
}
And each your "derived" classes derives from a funcPtr class which "auto generates" the specific alias declaration.

C++ Partial template specialization - design simplification

I am working on a pipeline/dataflow design pattern. I have a class 'algorithm data output' (AlgorithmOutput) that acts as an interface between two connected network segments. In particular, it provides method templates getOutput<size_t N> that are used for the data output from an object of the type 'data transmitter'.
The current design is based on the idea that users derive from the class AlgorithmOutput and provide a finite number of implementations of the method template getOutput<size_t N>. I also need to be able to allow users to provide their own custom return types from the method getOutput (i.e. the return type cannot be polymorphic). Moreover, it is necessary to have all implementations of getOutput to be able to access the same data set defined as a member of the class to which the methods belong.
The current solution uses partial explicit specialisation in the classes derived by the user to define the different implementations of the method getOutput. I would like to simplify the solution and would appreciate any ideas on how this can be done without losing the functionality of the current design.
EDIT: I am only concerned about the ease of implementation of the method getOutput from the perspective of the user. I am not concerned about how complex is the implementation of the base classes.
An example of the implementation of the derived class:
class PipeOutputClass: public AlgorithmOutput<PipeOutputClass>
{
public:
template <size_t N>
auto getOutput(size_t c_Idx) const
{
return getOutputImpl<N>::apply(this, c_Idx);
}
template<size_t N, typename S> friend struct getOutputImpl;
template<size_t N, typename = void>
struct getOutputImpl
{
static auto apply(
PipeOutputClass const* p_Self,
size_t c_Idx
)
{
throw std::runtime_error("Wrong template argument.");
}
};
template <typename S>
struct getOutputImpl<0, S>
{
static std::unique_ptr<double> apply(
PipeOutputClass const* p_Self,
size_t c_Idx
)
{
std::unique_ptr<double> mydouble(new double(10));
return mydouble;
}
};
template <typename S>
struct getOutputImpl<1, S>
{
static std::unique_ptr<int> apply(
PipeOutputClass const* p_Self,
size_t c_Idx
)
{
std::unique_ptr<int> myint(new int(3));
return myint;
}
};
};
You could use tag dispatching to avoid the need for partial specialization. A simplified version:
//we'll use this to overload functions based on a size_t template param
template <size_t N>
struct Size2Type{};
class PipeOutputClass
{
public:
template <size_t N>
auto getOutput(size_t c_Idx) const
{
//use Size2Type to tag dispatch
return getOutputImpl(Size2Type<N>{}, c_Idx);
}
//default version for when we don't explicitly provide an overload
template <size_t N>
auto getOutputImpl(Size2Type<N>, size_t c_Idx) const
{
throw std::runtime_error("Wrong template argument.");
}
//overload for when N = 0
std::unique_ptr<double> getOutputImpl (Size2Type<0>, size_t c_Idx) const
{
std::unique_ptr<double> mydouble(new double(10));
return mydouble;
}
//overload for when N = 1
std::unique_ptr<int> getOutputImpl (Size2Type<1>, size_t c_Idx) const
{
std::unique_ptr<int> myint(new int(3));
return myint;
}
};