从历史上看,我一直在使用特征类来保存信息,并将其应用到运行相同“算法”的“通用”函数中。仅在特征类上有所不同。例如: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
下面,我创建了一个继承的类层次结构。在此示例中,我有一个基本的示例,该示例将所有参数默认设置为某种值(本例中为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;
}
如何使setter类中的“样板”更通用?我不能像上面的示例中那样使用特征,因为我不能将静态函数与对象联系在一起。那么有没有办法使样例更常见?
说有选择符的某处
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方法绑定到静态函数(事后看来,这并没有。听起来不是个好主意...但是我想反弹我的主意)
答案 0 :(得分:1)
无论谁进行实际调用,都需要使用一种或另一种方式引用该对象。因此,假设您希望perform_action
执行实际的调用,则必须传递参数。
现在,如果您确实想在Base
中存储static
的哪个函数作为thing_traits
进行调用而不传递参数,则可以利用指向成员函数的指针:
template <>
struct thing_traits<THINGA>
{
static constexpr int (Base::*first_function)() = &Base::get_thing_one;
...
}
template < thing_select T, typename TT = thing_traits<T>>
int perform_action(Base & b)
{
return (b.*TT::first_function)() + ...;
}
您还可以通过返回一个为您进行调用的函数对象(内部函数带有参数)来进行播放。
这完全取决于您需要打电话给谁,以及您认为每个类/模板中都有哪些信息/依赖项。