How to automatically make set and get methods? - c++

I accept onathan Wakely's comment as answer. Thank you! The below is original post.
[original post]
Have an idea about making set and get methods in a class automatically as shown below
template<class T>
class Has
{
public:
template<class U>
const U& get() const;
template<>
const T& get<T>() const
{
return m_t;
}
template<class U>
void set(const U& t);
template<>
void set<T>(const T& t)
{
m_t = t;
}
private:
T m_t;
};
An example
class Door {};
class Window {};
class House
: public Has<Door>
, public Has<Window>
{};
House house;
// set
house.set(Door());
house.set(Window());
// get
const Door& door = house.get<Door>();
const Window& window = house.get<Window>();
If the components' types are different and their type names are readable, the code shown above is fine. But if the type name is not readable, such as the area of the house has a type double, I'd like to use
house.get<Area>(); // or
house.get<AREA>(); // where the template argument can be a const integer
other than
house.get<double>();
And if there are two components with double type, such as area and volume, how to deal with the complex? Thanks a lot!
There is a way to wrap the double as a new type like
template<class T>
class Wrap
{
public:
Wrap(const T& value = T())
: m_value
{}
operator T()
{
return m_value;
}
private:
T m_value;
};
class Area
: public Wrap<double>
{};
To doing this, is there any performance affection? Thanks.
Following jweyrich's suggestion, add the following code
template<class Name, class T>
class With
{
public:
template<class U>
const U& get() const;
template<>
const T& get<Name>() const
{
return m_t;
}
template<class U>
void set(const U& t);
template<>
void set<Name>(const T& t)
{
m_t = t;
}
private:
T m_t;
};
I think this work perfectly.
An example
class Door {};
class Window {};
class Area {}; // Empty, just a name holder
class Volume {}; // Another a name holder
class House
: public Has<Door>
, public Has<Window>
, public With<Area, double>
, public With<Volume, double>
{};
House house;
// set
house.set(Door());
house.set(Window());
house.set<Area>(3000);
house.set<Volume>(30000);
// get
const Door& door = house.get<Door>();
const Window& window = house.get<Window>();
double area = house.get<Area>();
double volume = house.get<Volume>();
Any one know for the template inheritance, is there any performance reduction? In my opinion, I think there is not. Thanks a lot!

Related

Add a method to templated class for specific type

For example, I have a class template:
template <typename T>
class base {
public:
void set(T data) { data_=data; }
private:
T data_;
};
And for a certain type I would like to add a function, but also have functions from the template class.
template <>
class base<int>{
public:
void set(int data) { data_=data; }
int get(){ return data_;} //function specific to int
private:
int data_;
}
How to do that without copying all members from the template class?
With inheritance:
template <typename T> struct extra {};
template <> struct extra<int> {
public:
int get() const;
};
template <typename T>
class base : public extra<T> {
friend class extra<T>;
public:
void set(T data) { data_=data; }
private:
T data_ = 0;
};
int extra<int>::get() const{ return static_cast<const base<int>*>(this)->data_;}
Demo
You can do this by using enable_if from type_traits to enable the get function only when the template parameter is int. One example is shown below.
#include <type_traits>
template <typename T>
class base {
public:
template <typename X=T,
std::enable_if_t< std::is_same<X,typename T>::value
&& std::is_same<X,int>::value, bool> = false>
int get() { return data_; }
void set(T data) { data_=data; }
private:
T data_;
};

Template constructor resolution based on existence of method or free-function

Problem
Motivated by Sean Parent's "Runtime Polymorphism" I implemented a Serializable class that uses type-erasure to dispatch Serializable::serialize(...) ⟶ obj.serialize(...), where obj is a wrapped object.
struct Serializable
{
template <typename T>
Serializable(T obj)
: m_self(std::make_unique<Model<T> >(std::move(obj))) {}
/// Writes itself to a write storage
void serialize(Storage& outStream)
{ return m_self->serialize(outStream); }
private:
struct Concept
{
virtual ~Concept() = default;
virtual void serialize(Storage& outStream) = 0;
};
template <typename T>
class Model final : public Concept
{
public:
Model(T x) : m_data(std::move(x)) {}
private:
void serialize(Storage& outStream) override
{ m_data.serialize(outStream); }
private:
T m_data;
};
private:
std::unique_ptr<Concept> m_self;
};
Now I would like to extend Serializable with another model class that would dispatch Serializable::serialize(...) to a free function with obj as an argument: Serializable::serialize(...) ⟶ serialize(obj, ...)
Then I would like a template constructor of Serializable to decide which model to use by checking the existence of either T::serialize(...) or serialize(const T&, ...)
Question
Is it possible by any means (e.g., SFINAE) to automatically construct Serializable so that it uses a method serialization if possible and free-function serialization otherwise?
Feel free to use any C++ standard up to C++17.
You can devise your own trait to find out whether the class has the correct serialize member. There are several ways to do it, this is one of them:
template <class T, class = void>
struct HasMemberSerialize : std::false_type
{};
template <class T>
struct HasMemberSerialize<T, std::void_t<decltype(std::declval<T>().serialize(std::declval<Storage&>()))>> : std::true_type
{};
[Live example]
Then, add a new template parameter to Model and use the trait to find its argument:
struct Serializable
{
template <typename T>
Serializable(T obj)
: m_self(std::make_unique<Model<T, HasMemberSerialize<T>::value> >(std::move(obj))) {}
/// Writes itself to a write storage
void serialize(Storage& outStream)
{ return m_self->serialize(outStream); }
private:
struct Concept
{
virtual ~Concept() = default;
virtual void serialize(Storage& outStream) = 0;
};
template <typename T, bool Member>
class Model;
private:
std::unique_ptr<Concept> m_self;
};
template <typename T>
class Serializable::Model<T, true> final : public Serializable::Concept
{
public:
Model(T x) : m_data(std::move(x)) {}
private:
void serialize(Storage& outStream) override
{ m_data.serialize(outStream); }
private:
T m_data;
};
template <typename T>
class Serializable::Model<T, false> final : public Serializable::Concept
{
public:
Model(T x) : m_data(std::move(x)) {}
private:
void serialize(Storage& outStream) override
{ serialize(m_data, outStream); }
private:
T m_data;
};

Reduce code duplication in class template specialization (array<Unique_ptr>)

How to reduce code duplication of a class that is template specialized?
I am trying to create a class (MyArray) that acts like std::vector but receives raw-pointer as parameter in some functions.
Here is a simplified version of it :-
template<class T> class MyArray{
T database[10];
public: T& get(int index){return database[index];}
void set(int index, T t){
database[index]=t;
}
};
template<class T> class MyArray<std::unique_ptr<T>>{
T* database[10];
public: T*& get(int index){return database[index];}
void set(int index, std::unique_ptr<T> t){
T* tmp=t.release();
database[index]=tmp;
}
};
Here is a test:-
class B{};
int main() {
MyArray<B> test1;
MyArray<B*> test2;
MyArray<std::unique_ptr<B>> test3;
test3.set(2,std::make_unique<B>()));
return 0;
}
Question: Please demonstrate an elegant way to reduce the above code duplication in MyArray.
A solution that I wished for may look like :-
template<class T> class MyArray{
using U = if(T=std::uniquePtr<X>){X*}else{T};
U database[10];
public: U& get(int index){return database[index];}
void set(int index, T t){
U u = convert(t);//<-- some special function
database[index]=u;
}
};
There might be some memory leak / corruption. For simplicity, please overlook it.
I just want an idea/rough guide. (no need to provide a full run-able code, but I don't mind)
In real life, there are 20+ function in MyArray and I wish to do the same refactoring for many classes.
Edit: I have (minor) edited some code and tag. Thank AndyG and Jarod42.
Maybe can you delegate the implementation details to a struct you provide to your class, and you specialize this struct, not MyArray:
template <typename T>
struct Policy {
using type = T;
static type convert(T t) { ... }
};
template <typename T>
struct Policy<std::unique_ptr<T>> {
using type = T*;
static type convert(T t) { ... }
};
template <typename T, typename P = Policy<T>>
class MyArray
{
using type = typename P::type;
void set(int index, T t) { type result = P::convert(t); }
};
You might think about using a common base class for the common functionality:
template<class T>
class Base{
protected:
T database[10];
public:
T& get(int index){return database[index];}
};
template<class T>
class MyArray : public Base<T>{
public:
void set(int index, T t){
this->database[index]=t;
}
};
template<class T>
class MyArray<std::unique_ptr<T>> : public Base<T*>
{
public:
void set(int index, std::unique_ptr<T>&& t){
T* tmp=t.release();
this->database[index]=tmp; //a little different
}
};
Demo

Accessing private member variables inside public member function

In function myfun is there a way to access rhs.var without writing a public function which returns var? Also, as I understand, this happens because rhs could be a different type... Is this correct?
#include <iostream>
template<class T>
class foo
{
private:
T var;
public:
foo(T v) : var(v) {}
template<class Type>
void myfun(foo<Type>& rhs)
{
auto i = rhs.var; //BOOM
}
};
int main()
{
foo<int> a = 5;
foo<double> b = 2.2;
a.myfun(b);
}
Suggested Solutions
You could either provide a public accessor to your private member variable:
template<class T>
class foo {
T var;
public:
foo(T v) : var(v) {}
T getVar() const { return var; }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
template<class Type>
void myfun(foo<Type>& rhs) {
auto i = rhs.getVar();
^^^^^^^^
}
};
Or as already Dieter mentioned in the comments you could make your template class a friend:
template<class T>
class foo {
T var;
template <class> friend class foo;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
public:
foo(T v) : var(v) {}
template<class Type>
void myfun(foo<Type>& rhs) {
auto i = rhs.var;
}
};
Overview
The reason why the template member function myfun is not granted access to private member variable var of class template foo is that the compiler interprets class foo<Type> and class foo<T> as completely different class types, even though they would originate from the same template class definition. Thus, as being different class types the one cannot access the private members of the other.
you can define the second type as fried like:
template<class T>
class foo
{
private:
T var;
public:
foo(T v) : var(v) {}
template<class Type>
void myfun(foo<Type>& rhs)
{
auto i = rhs.var; //BOOM
}
template<class Type>
friend class foo;
};
live example

How can I modify my boost::any like class

I'm trying to implement boost::any like class:
struct any
{
private:
struct holderBase
{
virtual ~holderBase(){}
};
template<typename T>
struct holder : public holderBase
{
T content;
holder(const T& value) : content(value){}
holder(const holder<T>& other) : content(other.content){}
};
holderBase *hl;
public:
template<typename T>
any(const T& data = T()) { hl = new holder<T>(data); }
any(const any& other) { hl = other.hl; }
template<typename T>
T get()
{
if(holder<T>* p_hl = dynamic_cast<holder<T>*>(hl))
return p_hl->content;
else
throw std::runtime_error("std::runtime_error");
}
};
I use a holder class (inherited by holderBase) to store the data.
How can I modify the any::get() function (or even modify the whole code) so that it doesn't need a template parameter (the get() function)?
You could do it like this:
template<typename T>
T get(T *ptr);
Similar to the C time function, you would return the result, as well as store it in ptr.
Edit: You could also override the casting operator:
template<typename T>
operator T()
{
return get<T>();
}
Which will implicitly do what you want.
Stating the obvious: If you don't want to return 1 particular type to the user then it needs to be templated. There's nothing you can do about it.