【问题标题】:how to create templated-like namespace for member functions如何为成员函数创建类似模板的命名空间
【发布时间】:2022-01-07 08:12:58
【问题描述】:

我正在尝试定义一个命名空间/结构,其中包含存储特定实现的函数指针(假设一个包含多个函数的结构)。目前,使用以下结构一切正常:

class foo{
    int a;
    int b;

public:
    explicit foo(int _a, int _b) : a(_a), b(_b) {};
    std::function<int(int)> bar(int num) = [=](int num) -> int{
         // here I need to know a and b
         //do something with num and return 
    }
}

这个类包含几个函数,每个函数都必须知道 a 和 b。问题是我必须创建类的实例并设置参数 a 和 b,我宁愿省略。 在另一个类中,我只通过使用它的功能来使用这个类。即

class foo2{
    //some other parameters
    int a, b;
    std::function<...> fun1, fun2,...;
public:
    foo2(int a, int b, ....){this->a = a; this->b = b;};
    setFuncs(){
        foo instance(a, b); 
        this->fun1 = [instance](int num){ return instance.bar(num);}
        this->fun2 = ...
    }
}

但我想省略每次都创建一个新的类实例(从某种意义上说,我在同一个类中重复上述行为,但在代码中的另一个位置)。我试图将这个类模板化为

template<int a, int b>
class foo{
...
}

所以我可以将函数分配为:

this->fun1 = foo<a,b>::bar;

但是我需要在编译时知道 a 和 b,这是不可能的。这些参数在类 foo2 中设置一次。我意识到整体代码可能并不干净,正如您所见,我是物理学家,而不是 IT 人。一种方法是将类 foo 的实例存储在类 foo2 中,并为整个类初始化一次,并让函数 fun1、fun2、... 通过引用这些指针来访问,但我正在寻找是否有另一个方式(可能是类之类的模板,我不需要在编译时知道这些值)。 此外,我无法在此处粘贴整个代码,因为它在多个文件中包含数千行,并且很难描述代码的作用。如果这可能是一个愚蠢或微不足道的问题,我感谢任何帮助并道歉(我不严格地从事 IT 工作,我是一名物理学家;))

【问题讨论】:

  • 我认为您可能遇到了 XY 问题。我觉得你想要某种预制的函数参数化,但我没有清楚地理解你的意图。您需要提供某些功能但具有比单个函数调用更大范围的预定义输入的对象。您可能会错过某个设计模式,或者可能只是使 (XY) 问题过于复杂。
  • “问题是我必须创建类的实例并设置参数 a 和 b,我宁愿省略” - 如果您希望任何状态保持比 a 更长的时间,这是不可避免的单个函数调用。您希望某些东西保留/应用更长时间,因此(除非它是编译时数据)状态是不可避免的。所有解决方案都只是封装数据的方式不同——结构成员、捕获 lambda、std::function 和状态。

标签: c++ function class templates namespaces


【解决方案1】:

由于您希望某些输入数据比单个函数调用保留更长时间,除非它是完全编译时数据,否则运行时状态是不可避免的。问题是如何您希望这些数据被封装 - 不同的方法会产生非常不同的(主观)感受它们的方便程度。

根据您的使用示例:

this->fun1 = foo<a,b>::bar;

如果你想避免状态(或者更确切地说封装它),你可以创建一个工厂来为你创建函数:

std::function<int(int)> make_func(int a, int b)
{
    return [=](int x){ return actual_function(a, b, x); };
}

this->fun1 = make_func(a, b); // now std::function will hold lambda's captured state

这个话题通常被称为部分应用,我猜 boost 或其他库已经有很多支持这种操作的代码。

【讨论】:

  • 这实际上是一个非常有趣的ide,谢谢!我可能会用它!我目前正在考虑如何概括这个想法,因为我在 foo 类中有大约 10 个函数。一方面,我可以创建这样的构造,并在 switch-case 声明中通过枚举选择适当的函数并整体替换类,另一方面,我可以保留类并为每个函数单独创建一个工厂。两种方式都应该有效,是否有理由选择一种而不是另一种?
  • 我不明白你的问题。 foo 类中的 10 个函数 - 但为什么呢?他们是否共享任何东西(例如ab 变量)。为什么需要枚举来选择实现?为什么不立即调用具体实现?
  • 抱歉回复晚了。是的,它们都共享 a、b,我想省略将它们作为变量传递给函数。一般来说,我指的代码是:
  • pastebin.com/kq4tksKd 代码很长,通常我的问题是指创建类 __builtins 的实例,如在类运算符的构造函数之一中所见。一些不同的类使用枚举创建类型运算符的对象,然后选择适当的函数,这就是为什么我想省略创建运行时状态的原因。编辑:这里 a,b 表示为 'L' 和 'config'
  • 一些状态是不可避免的,std::function 也有一些内部状态(如果你知道它是如何实现的)。我大致知道您想要什么,但是 1)我仍然对您希望如何抽象它有疑问 2)如果您发布 MCVE 以改进或未完成的 MCVE 进行修改(代码中有一些空白),这对我来说会容易得多填写)。您发布的粘贴无法编译,可能会大大减少。
【解决方案2】:

您可以在ab 的值已知的foo 构造函数中创建lambda。

然后您还可以捕获 this 以使用成员变量(以防它们在 lambda 创建和调用之间发生变化)。

class foo
{
    int a;
    int b;

public:
    // No need for explicit since this isn't a "conversion" constructor
    foo(int a, int b) : a(a), b(b)
    {
        bar = [this](int x)
        {
            // Use the argument together with this->a and this->b...
            return some_value;
        };
    }

    std::function<int(int)> bar;
};

【讨论】:

  • 在构造函数中声明函数 bar 与在构造函数调用之外将其设置为 const 有什么区别?有什么理由可以更好吗?通过创建一个实例,其他类成员(如 bar)使用设置的参数 a、b 进行设置,对于这个特定的实例不会改变
  • @Qant123 在任何成员函数(包括构造函数)之外,都无法访问this。如果没有对象,则无法访问任何(非静态)成员变量。
  • 我明白了。现在我很困惑我的方法是如何工作的。通过在 lambda 中使用 = 来捕获在构造函数外部声明的函数仍然是新的非静态数据成员。但是这种方法容易出错,谢谢!
猜你喜欢
  • 1970-01-01
  • 2015-10-06
  • 2017-05-27
  • 1970-01-01
  • 1970-01-01
  • 2021-05-24
  • 2012-10-14
  • 2010-10-04
  • 2018-08-26
相关资源
最近更新 更多