How to apply Template Method Pattern for functions with different signatures? - c++

How does one provide a unified interface to sets of functions, that are used in the same way? To illustrate, please look at the set of given library functions:
/* existing library functions */
/* the signatures are different: some return int, some float */
/* set of input related functions */
int getInputValue() { return 42; }
size_t getInputSize() { return 1; }
/* set of output related functions */
int getOutputValue() { return 21; }
size_t getOutputSize() { return 1; }
/* set of parameter related functions */
float getParameterValue() { return 3.14; }
size_t getParameterSize() { return 1; }
and assume they are used in the same way:
if (getSize() > 0) {
T value = getValue()
A) What is a good way to provide getSize() and getValue()?
I first though that Template Method Pattern is what I want, but I couldn't apply it, because in contrast to the Worker in the Template Method Pattern, my functions have different signatures.
So what I did instead:
/* I want to provide a uniform interface */
/* the specific part of inputs, outputs and parameters is in the traits */
struct input_traits {
typedef int value_type;
static int getValue() { return getInputValue(); }
static size_t getSize() { return getInputSize(); }
};
struct output_traits {
typedef int value_type;
static int getValue() { return getOutputValue(); }
static size_t getSize() { return getOutputSize(); }
};
struct parameter_traits {
typedef float value_type;
static float getValue() { return getParameterValue(); }
static size_t getSize() { return getParameterSize(); }
};
/* the common part (they are used in the same way) is in the Helper */
template<typename traits>
class CommonUsage {
public:
void use()
{
if (traits::getSize() > 0) {
typename traits::value_type value = traits::getValue();
}
}
};
int main()
{
CommonUsage<input_traits>().use();
CommonUsage<output_traits>().use();
CommonUsage<parameter_traits>().use();
}
B) Is this a good approach?

A. If i understood your question correctly you should use an abstract class.
Look at the next code, it essentially does the same as your code.
This is how i would do it.
#include <iostream>
template <typename value_type>
class Traits {
public:
virtual value_type getValue() const = 0;
virtual size_t getSize() const = 0;
virtual ~Traits() { }
};
class input_traits: public Traits <int>{
public:
virtual int getValue() const {
return 42;
}
virtual size_t getSize() const {
return 1;
}
};
class parameter_traits: public Traits <double>{
public:
virtual double getValue() const {
return 3.14;
}
virtual size_t getSize() const {
return 1;
}
};
class CommonUsage {
public:
template <typename value_type>
void use(const Traits<value_type>& traitsObject) {
if (traitsObject.getSize() > 0) {
std::cout << traitsObject.getValue();
}
}
};
int main() {
CommonUsage().use(parameter_traits());
return 0;
}

As an alternative to user's answer (this time using template specialization) is:
template <class T>
struct traits {
T getValue() const { throw std::runtime_exception("..."); }
size_t getSize() const { return 0; }
};
template <>
struct traits<int> {
int getValue() const { return 42; }
size_t getSize() const { return 1; }
};
template <>
struct traits<float> {
int getValue() const { return 3.145; }
size_t getSize() const { return 1; }
};
// do template aliasing
using input_traits = traits<int>;
using parameter_traits = traits<float>;
struct CommonUsage {
template <typename T>
static void use(const traits<T> &traits) {
if (traits.getSize() > 0)
std::cout << traits.getValue() << std::endl;
}
};
int main(int arg, char **argv) {
CommonUsage::use(input_traits());
CommonUsage::use(parameter_traits());
}
There are advantages/disadvantages to both approaches. If you use template specialization, you don't pay the overhead of virtual methods.

Related

dynamically call same named function with different return type

I have a situation here...
I want to design a Factory where I can call a function with same name and no parameters but return different data Types. Based on the SubClassName I need to instantiate the Object.
Need help or lead on any design pattern to follow?
EDIT:
An abstract pseudo code...
class parent{
public:
virtual string getName() = 0;
//some virtual function.. not sure how to design. As the return type is dynamic.
*** getValue(){}
};
class A : public parent{
int x;
public:
virtual string getName(){ return "A";}
virtual int getValue(){retun x;}
};
class B : public parent{
string s;
public:
virtual string getName(){ return "B";}
virtual string getValue(){ return s;}
};
void main(){
string callingClass = "B";
parent * arrayPtrs[2];
arrayPtrs[0] = new A;
arrayPtrs[1] = new B;
for (loop through array, through iterator i){
if(arrayPtrs[i]->getName == callingClass ){
cout<<arrayPtrs[i]->getValue;
}
}
}
In C++ a function can only have one return type at a time, and you cannot change that dynamically.
However - as suggested by #mch - you can use template specializations. Keep in mind though, that this method is not dynamic. Your functions will be generated at compile time.
If I understood your question correctly, maybe this can be of help.
class MyObject1
{
//...
};
class MyObject2
{
//...
};
template<typename T>
struct Factory
{
constexpr static T gen();
};
template<>
struct Factory<MyObject1>
{
constexpr static MyObject1 gen()
{
return MyObject1(/*... whatever parameters you see fit ...*/);
}
};
template<>
struct Factory<MyObject2>
{
constexpr static MyObject2 gen()
{
return MyObject2(/*... whatever parameters you see fit ...*/);
}
};
int main()
{
auto myObj = Factory<MyObject1>::gen();
return 0;
}
Although this method seems fairly useless to me. You could simply call the desired constructor instead of this.
But then again, I'm not sure if this is what you thought of. If I made any mistakes please feel free, to correct me. I'll try to edit my answer best as I can.
EDIT:
To keep the virtual functionality too, the only way I can think of is type erasure: see https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Type_Erasure
The closest I could get to what you've asked for is this:
#include <iostream>
#include <string>
#include <any>
class parent {
public:
// you can use this too but I think type checking is more handy
// see in main function
/* virtual std::string getName() const = 0; */
virtual std::any getValue() const = 0;
};
class A : public parent {
public:
typedef int value_type;
private:
value_type x;
public:
A(value_type x) :
x(x)
{}
/* virtual std::string getName() const override { return "A"; } */
virtual std::any getValue() const override
{ return this->x; }
};
class B : public parent {
public:
typedef std::string value_type;
private:
value_type s;
public:
B(const value_type& s) :
s(s)
{}
/* virtual std::string getName() const override { return "B"; } */
virtual std::any getValue() const override
{ return this->s; }
};
int main(){
using callingClass = A;
parent* arrayPtrs[2];
arrayPtrs[0] = new A(42);
arrayPtrs[1] = new B("my string");
for (unsigned i = 0; i < sizeof(arrayPtrs) / sizeof(parent*); ++i)
{
// Note:
// dynamic cast will return nullptr if $callingClass
// is not a derived class
if (dynamic_cast<callingClass*>(arrayPtrs[i]))
std::cout << std::any_cast<callingClass::value_type>(arrayPtrs[i]->getValue()) << std::endl;
}
return 0;
}
I hope this one helps.
Note, that I used dynamic_cast to check the correct type. If you know a better solution, you can use that, too. But under these circumstances I couldn't think of any better.
EDIT2:
#include <iostream>
#include <string>
#include <tuple>
class some
{
using id = size_t;
template<typename T>
struct type { static void id() { } };
template<typename T>
static id type_id() { return reinterpret_cast<id>(&type<T>::id); }
template<typename T>
using decay = typename std::decay<T>::type;
template<typename T>
using none = typename std::enable_if<!std::is_same<some, T>::value>::type;
struct base
{
virtual ~base() { }
virtual bool is(id) const = 0;
virtual base *copy() const = 0;
} *p = nullptr;
template<typename T>
struct data : base, std::tuple<T>
{
using std::tuple<T>::tuple;
T &get() & { return std::get<0>(*this); }
T const &get() const& { return std::get<0>(*this); }
bool is(id i) const override { return i == type_id<T>(); }
base *copy() const override { return new data{get()}; }
};
template<typename T>
T &stat() { return static_cast<data<T>&>(*p).get(); }
template<typename T>
T const &stat() const { return static_cast<data<T> const&>(*p).get(); }
template<typename T>
T &dyn() { return dynamic_cast<data<T>&>(*p).get(); }
template<typename T>
T const &dyn() const { return dynamic_cast<data<T> const&>(*p).get(); }
public:
some() { }
~some() { delete p; }
some(some &&s) : p{s.p} { s.p = nullptr; }
some(some const &s) : p{s.p->copy()} { }
template<typename T, typename U = decay<T>, typename = none<U>>
some(T &&x) : p{new data<U>{std::forward<T>(x)}} { }
some &operator=(some s) { swap(*this, s); return *this; }
friend void swap(some &s, some &r) { std::swap(s.p, r.p); }
void clear() { delete p; p = nullptr; }
bool empty() const { return p; }
template<typename T>
bool is() const { return p ? p->is(type_id<T>()) : false; }
template<typename T> T &&_() && { return std::move(stat<T>()); }
template<typename T> T &_() & { return stat<T>(); }
template<typename T> T const &_() const& { return stat<T>(); }
template<typename T> T &&cast() && { return std::move(dyn<T>()); }
template<typename T> T &cast() & { return dyn<T>(); }
template<typename T> T const &cast() const& { return dyn<T>(); }
template<typename T> operator T &&() && { return std::move(_<T>()); }
template<typename T> operator T &() & { return _<T>(); }
template<typename T> operator T const&() const& { return _<T>(); }
};
using any = some;
class parent {
public:
// you can use this too but I think type checking is more handy
/* virtual std::string getName() const = 0; */
virtual any getValue() const = 0;
};
class A : public parent {
public:
typedef int value_type;
private:
value_type x;
public:
A(value_type x) :
x(x)
{}
/* virtual std::string getName() const override { return "A"; } */
virtual any getValue() const override
{ return this->x; }
};
class B : public parent {
public:
typedef std::string value_type;
private:
value_type s;
public:
B(const value_type& s) :
s(s)
{}
/* virtual std::string getName() const override { return "B"; } */
virtual any getValue() const override
{ return this->s; }
};
int main(){
using callingClass = A;
parent* arrayPtrs[2];
arrayPtrs[0] = new A(42);
arrayPtrs[1] = new B("my string");
for (unsigned i = 0; i < sizeof(arrayPtrs) / sizeof(parent*); ++i)
{
// Note:
// dynamic cast will return nullptr if $callingClass
// is not a derived class
if (dynamic_cast<callingClass*>(arrayPtrs[i]))
std::cout << arrayPtrs[i]->getValue()._<callingClass::value_type>() << std::endl;
}
return 0;
}
This snipped is in case you cannot use C++17 features, and is based on:
any class

C++ Similar functions using different data types

I have two functions which are exactly the same, except that one of them uses a stack for its operations and the other one uses a queue:
void doQueue()
{
std::queue<int> q;
...
...
q.push(someValue);
...
...
int tmp = q.front();
q.pop()
}
void doStack()
{
std::stack<int> s;
...
...
s.push(someValue);
...
...
int tmp = s.top();
s.pop()
}
I want to eliminate duplicate code. As queue uses the front function to retrieve the first value and stack uses the top function, I thought that templates may not work since functions with different names have to be called.
My other idea was to create an interface which will be as a wrapper to both data structures and I can pass around the one that I need.:
class Data
{
public:
virtual void push(const int v) = 0;
virtual int pop() = 0;
};
class StackData : public Data
{
private:
std::stack<int> _stack;
public:
virtual void push(const int v) {_stack.push(v);}
virtual int pop()
{
int ret = _stack.top();
_stack.pop();
return ret;
}
};
class QueueData : public Data
{
private:
std::queue<int> _queue;
public:
virtual void push(const int v) {_queue.push(v);}
virtual int pop()
{
int ret = _queue.front();
_queue.pop();
return ret;
}
};
void doData(Data& dataType)
{
...
dataType.push(someValue);
...
int tmp = dataType.pop();
}
void doQueue()
{
QueueData queueData;
doData(queueData);
}
void doStack()
{
StackData stackData;
doData(stackData);
}
But I think there should be an easier and better way to perform this operation.
Here's one way - a wrapper template with partial specialisation on underlying container type:
#include <stack>
#include <queue>
template<class Container>
struct generic_sequence_ops;
template<class T, class UnderlyingContainer>
struct generic_sequence_ops<std::stack<T, UnderlyingContainer>>
{
using container_type = std::stack<T, UnderlyingContainer>;
using value_type = typename container_type::value_type;
generic_sequence_ops(container_type& c) : c(c) {}
void add_one(value_type v)
{
c.push(std::move(v));
}
void remove_one()
{
c.pop();
}
value_type& current()
{
return c.top();
}
container_type& c;
};
template<class T, class UnderlyingContainer>
struct generic_sequence_ops<std::queue<T, UnderlyingContainer>>
{
using container_type = std::queue<T, UnderlyingContainer>;
using value_type = typename container_type::value_type;
generic_sequence_ops(container_type& c) : c(c) {}
void add_one(value_type v)
{
c.push(std::move(v));
}
void remove_one()
{
c.pop();
}
value_type& current()
{
return c.back();
}
container_type& c;
};
template<class Container>
auto make_generic_sequence_ops(Container& cont)
{
return generic_sequence_ops<std::decay_t<Container>>(cont);
}
template<class Container>
int doContainer(Container& cont)
{
auto s = make_generic_sequence_ops(cont);
s.add_one(6);
int val = s.current();
s.remove_one();
return val;
}
int main()
{
std::queue<int> q;
std::stack<int> s;
doContainer(q);
doContainer(s);
}

Store different templated classes in one container without losing information about it's type

I'm currently working on a project where a client part of my application has to be able to create custom templated classes on the server. The server part has to keep track of these created classes and has to remember the types with which the classes has been instantiated. The problem is, that there are around 36 different class-template-combinations that are valid in my application. I'm currently struggling to keep track of these different types in a collection without losing information about my instances.
I'm currently using something like this:
#include <memory>
#include <type_traits>
#include <vector>
enum class data_type : std::uint8_t {
type_int = 1,
type_float,
type_double
};
enum class class_type : std:: uint8_t {
type_A = 1,
type_B
};
struct X {
virtual data_type get_data_type() = 0;
virtual class_type get_class_type() = 0;
};
template <typename T>
struct A : X {
data_type get_data_type() override
{
if (std::is_same<T, int>::value) {
return data_type::type_int;
} else if (std::is_same<T, float>::value) {
return data_type::type_float;
} else if (std::is_same<T, double>::value) {
return data_type::type_double;
} else {
/* ... */
}
}
class_type get_class_type() override
{
return class_type::type_A;
}
};
template <typename T>
struct B : X {
data_type get_data_type() override
{
if (std::is_same<T, int>::value) {
return data_type::type_int;
} else if (std::is_same<T, float>::value) {
return data_type::type_float;
} else if (std::is_same<T, double>::value) {
return data_type::type_double;
} else {
/* ... */
}
}
class_type get_class_type() override
{
return class_type::type_B;
}
};
struct Storage {
template <typename T, template <typename> class Class>
void create() {
Class<T>* t = new Class<T>();
_classes.push_back(std::unique_ptr<X>(t));
}
std::vector<std::unique_ptr<X>> _classes;
};
but I'm wondering if this is the way to go or if there is a more elegant way. Here I would have to always switch through the enums to get the full type out of my Storage class, something like:
switch(_classes.front()->get_class_type()) {
case class_type::type_A:
{
switch(_classes.front()->get_data_type()) {
case data_type::type_int:
{
/* I finally know that it is A<int> */
}
/* ... */
Thanks in advance.
You can consider using std::variant and the std::visit pattern
auto var = std::variant<int, float, double>{};
// assign var to value
std::visit([](auto& value) {
using Type = std::decay_t<decltype(value)>;
if constexpr (std::is_same<Type, int>{}) {
// is an int
} else if (std::is_same<Type, float>{}) {
// is float
} else if (std::is_same<Type, double>{}) {
// is double
}
}, var);
If the if constexpr looks ugly to you then you can substitute it with a handrolled visitor class as well.
class Visitor {
public:
void operator()(int& value) { ... }
void operator()(float& value) { ... }
void operator()(double& value) { ... }
};
auto var = std::variant<int, float, double>{};
// assign var to value
std::visit(Visitor{}, var);
As mentioned in the comments to the question, this is a viable approach that could help:
#include<vector>
#include<memory>
struct Counter {
static int next() {
static int v = 0;
return v++;
}
};
template<typename>
struct Type: Counter {
static int value() {
static const int v = Counter::next();
return v;
}
};
struct X {
virtual int get_data_type() = 0;
virtual int get_class_type() = 0;
};
template <typename T>
struct A : X {
int get_data_type() override {
return Type<T>::value();
}
int get_class_type() override {
return Type<A<T>>::value();
}
};
template <typename T>
struct B : X {
int get_data_type() override {
return Type<T>::value();
}
int get_class_type() override {
return Type<B<T>>::value();
}
};
struct Storage {
template <typename T, template <typename> class Class>
void create() {
Class<T>* t = new Class<T>();
_classes.push_back(std::unique_ptr<X>(t));
}
std::vector<std::unique_ptr<X>> _classes;
};
int main() {
Storage s;
s.create<int, A>();
if(Type<int>::value() == s._classes.front()->get_class_type()) {
//...
};
}
See it running on wandbox.

How to use an integer id to identify a class in a class hierarchy automatically?

For example, I have a base class A and its sub-classes B, C and so on. B and C can also has its sub-classes. The structure is a tree with root A. And each class in the tree is assigned a different integer to identify itself. There is no restriction on the integer id's values and orders. Just make sure they are different for different classes.
My question is how to do it smartly (or automatically) by using like template techniques since manual assignment is error-prone. Any way to get the id is fine, like
class A
{
public:
static const id = ...;
};
or
template<class A>
struct Id
{
enum { value = ... };
};
Easiest way is just a function
int nextId() {
static int rval = 1;
return rval++;
}
class A { public: static const id = nextId(); };
class B { public: static const id = nextId(); };
class C { public: static const id = nextId(); };
That will work so long as you do not need to use the IDs in dynamic initialization at the start of the program.
Edit: if that is not sufficient, the next step up is to do the same thing with static variables in a template. This works across compilation units, but is still dynamic initialization time.
template <typename DummyT = void>
struct CommonCounter
{
public:
static int nextId() {
static int rval = 1;
return rval ++;
}
};
template <typename T>
struct IdFor
{
static int value()
{
static int rval = CommonCounter<>::nextId();
return rval;
}
};
class A { public: static const id = IdFor<A>::get(); };
You could do something like this. This should give the same order on the same compiler. You could also modify how you key things to get a known order and detect problems at initialisation time. Simple implementation, not tested.
#include <typeinfo>
class A {
public:
virtual ~A();
static void register_type(std::type_info const& t);
int id() const;
};
template<class T>
struct DoInitA
{
DoInitA() { A::register_type(typeid(T)); }
};
class B : public A
{
static DoInitA<B> s_a_init;
public:
~B() { }
};
//
// Implementation file.
//
#include <vector>
#include <functional>
namespace {
struct TypeinfoLess {
typedef std::reference_wrapper<const std::type_info> value_type;
bool operator()(value_type const& lhs, value_type const& rhs) const {
return lhs.get().before(rhs.get());
}
};
}
typedef std::vector<std::reference_wrapper<const std::type_info>> TypeVector;
static TypeVector s_types;
static bool s_init_complete = false;
A::~A() { }
void A::register_type(std::type_info const& t)
{
static int s_counter = 0;
if (s_init_complete)
throw std::runtime_error("Late initialisation");
s_types.push_back(std::reference_wrapper<const std::type_info>(t));
}
int A::id() const
{
if (!s_init_complete) {
sort(s_types.begin(), s_types.end(), TypeinfoLess());
s_init_complete = true;
}
for (size_t i = 0; i < s_types.size(); ++i)
if (s_types[i].get() == typeid(*this)) return i;
throw std::runtime_error("Uninitialised type");
}

Appending values to a variant of containers

I have a container variant as follows:
typedef boost::variant<std::vector<int>, std::vector<std::string> > Container;
And I populate a Container object from a ValueContainer object (a C struct) as follows:
class ContainerAppender: public boost::static_visitor<>
{
public:
void setValueToAppend(const Value* value){
_value = value;
}
void operator()(std::vector<int>& container) const {
container.push_back(_value->value.i);
}
void operator()(std::vector<std::string>& container) const {
container.push_back(_value->value.s);
}
...
private:
const Value* _value;
};
void fillContainer(Container& container, ValueContainer* cContainer) {
if(cContainer) {
ContainerAppender append;
for(int i = 0; i < cContainer->nunberOfValues; i++) {
append.setValueToAppend(&cContainer->values[i]);
boost::apply_visitor(append, container);
}
}
}
I am not free to change the C structures.
I don't like my solution for populating the container as I am visiting for every loop despite the fact that the container type never changes. It feels that there is a better way of doing. Can you help?
here's the C union:
typedef struct Value {
union {
int i;
const char* s;
} value;
} Value_T;
typedef struct ValueContainer {
Type type;
unsigned int numberOfValues;
Value *values;
} ValueContainer_T;
Is the visitor really necessary? Consider this:
template<typename T>
T value_get(Value_T const &c_variant) {
return T();
}
template<>
int value_get<int>(Value_T const &c_variant) {
return c_variant.i;
}
template<>
const char* value_get<const char*>(Value_T const &c_variant) {
return c_variant.s;
}
template<typename T>
std::vector<T> fill_vector(ValueContainer_T const& c_container) {
std::vector<T> cpp_container(c_container.numberOfValues);
for(size_t i = 0; i < c_container.numberOfValues; ++i)
cpp_container[i] = value_get<T>(c_container.values[i]);
return cpp_container;
}
Looks simpler to me.