Исторически я использовал классы черт, чтобы хранить информацию и применять ее в «универсальной» функции, которая выполняет тот же «алгоритм».Отличались только чертой класса.Например: https://onlinegdb.com/ryUo7WRmN
enum selector { SELECTOR1, SELECTOR2, SELECTOR3, };
// declaration
template < selector T> struct example_trait;
template<> struct example_trait<SELECTOR1> {
static constexpr size_t member_var = 3;
static size_t do_something() { return 0; }
};
template<> struct example_trait<SELECTOR2> {
static constexpr size_t member_var = 5;
static size_t do_something() { return 0; }
};
// pretend this is doing something useful but common
template < selector T, typename TT = example_trait<T> >
void function() {
std::cout << TT::member_var << std::endl;
std::cout << TT::do_something() << std::endl;
}
int main()
{
function<SELECTOR1>();
function<SELECTOR2>();
return 0;
}
Я не уверен, как создать «универсальные» алгоритмы, это при работе с полиморфными классами.
Например: https://onlinegdb.com/S1hFLGC7V
Ниже я создал унаследованную иерархию классов.В этом примере у меня есть базовый пример catch-all, который по умолчанию использует все параметры (0 в данном случае).И затем каждый производный набор классов переопределяет определенные методы.
#include <iostream>
#include <memory>
#include <type_traits>
#include <assert.h>
using namespace std;
struct Base {
virtual int get_thing_one() {
return 0;
}
virtual int get_thing_two() {
return 0;
}
virtual int get_thing_three() {
return 0;
}
virtual int get_thing_four() {
return 0;
}
};
struct A : public Base {
virtual int get_thing_one() override {
return 1;
}
virtual int get_thing_three() override {
return 3;
}
};
struct B : public Base {
virtual int get_thing_one() override {
return 2;
}
virtual int get_thing_four() override{
return 4;
}
};
Здесь я создал простую фабрику, не элегантную, а для иллюстративных целей
// example simple factory
std::shared_ptr<Base> get_class(const int input) {
switch(input)
{
case 0:
return std::shared_ptr<Base>(std::make_shared<A>());
break;
case 1:
return std::shared_ptr<Base>(std::make_shared<B>());
break;
default:
assert(false);
break;
}
}
Так что это интересующий класс.Это класс «что-то» делает с данными из классов выше.Приведенные ниже методы представляют собой простой пример сложения, но представьте себе более сложный алгоритм, который очень похож для каждого метода.
// class that uses the shared_ptr
class setter {
private:
std::shared_ptr<Base> l_ptr;
public:
setter(const std::shared_ptr<Base>& input):l_ptr(input)
{}
int get_thing_a()
{
return l_ptr->get_thing_one() + l_ptr->get_thing_two();
}
int get_thing_b()
{
return l_ptr->get_thing_three() + l_ptr->get_thing_four();
}
};
int main()
{
constexpr int select = 0;
std::shared_ptr<Base> example = get_class(select);
setter l_setter(example);
std::cout << l_setter.get_thing_a() << std::endl;
std::cout << l_setter.get_thing_b() << std::endl;
return 0;
}
Как я могу сделать «шаблон» внутри класса сеттера более универсальным?Я не могу использовать черты, как в примере выше, потому что я не могу связать статические функции с объектом.Так есть ли способ сделать шаблонный пример более распространенным?
Где-то по линии наличия селектора, скажем
enum thing_select { THINGA, THINGB, };
template < thing_select T >
struct thing_traits;
template <>
struct thing_traits<THINGA>
{
static int first_function() --> somehow tied to shared_ptr<Base> 'thing_one' method
static int second_function() --> somehow tied to shared_ptr<Base> 'thing_two' method
}
template <>
struct thing_traits<THINGB>
{
static int first_function() --> somehow tied to shared_ptr<Base> 'thing_three' method
static int second_function() --> somehow tied to shared_ptr<Base> 'thing_four' method
}
// generic function I'd like to create
template < thing_select T, typename TT = thing_traits<T> >
int perform_action(...)
{
return TT::first_function(..) + TT::second_function(..);
}
В идеале я хотел бы изменить приведенный выше класс на что-тостроки
// Inside setter class further above
int get_thing_a()
{
return perform_action<THINGA>(...);
}
int get_thing_b()
{
return perform_action<THINGB>(...);
}
Ответ, возможно, я не могу, и мне нужно передать int shared_ptr в качестве параметра и вызвать конкретные методы, которые мне нужны, вместо того, чтобы пытаться привязать метод shared_ptr кстатическая функция (задним числом это не звучит как хорошая идея ... но я хотел отказаться от своей идеи)