【问题标题】:Is there any pattern equivalent to virtual template function?是否有任何与虚拟模板功能等效的模式?
【发布时间】:2020-09-12 01:33:19
【问题描述】:

我正在开发一个监控工具,我专注于降低运行时开销和一个简单的 API。对于低开销的运行时开/关切换,我选择使用状态模式,并为了简化模板参数包的使用。

现在我第一次在分离编译时和运行时的线上进行斗争,当然不能让虚拟模板函数工作。

考虑到以下限制,我正在寻找解决方法或等效解决方案:

  • “禁用”状态的最低运行时成本
  • 灵活的 API
  • 预 C++17 合规性

如果不可能,那也没关系...

代码示例:

static struct /*Disabled*/ State
{
    template <typename... Args>
    /*virtual*/ void operator()(const char * category, Args&&... args) { /*noop*/ }
} 
disabled;

static struct Enabled : State
{
    template <typename... Args>
    /*virtual*/ void operator()(const char * category, Args&&... args) { /*processing category and args*/ }
} 
enabled;

struct Monitor
{
    static State* state;

    template <typename... Args>
    static void write(const char * category, Args&&... args)
    {
        state->operator()(category, std::forward<Args>(args)...);
    }
};

State* Monitor::state = &enabled;

int main()
{
    Monitor::write("BulletCount", 42);
    Monitor::write("Spell", "EnergyShield", true);
}

上面的代码可以编译,但是如果没有虚拟继承,我永远无法达到Enabled 状态。删除模板并进行大量重载可以做到这一点,但如果可以避免,它可能会成为一个非常优雅的解决方案。

【问题讨论】:

  • FWIW 这被称为表达问题,主要方法(多方法)已经提出了十多年的尘埃落定(stroustrup.com/multimethods.pdf)。有一个有趣的库,叫做 yomm2 (github.com/jll63/yomm2),它实现了多方法。
  • @rustyx 在运行时,我会将其添加到帖子中。

标签: c++ templates monitoring template-meta-programming


【解决方案1】:

您可以尝试另一种维护模板的方法(基于组合而不是继承),如下所示:

enum state_enum
{
    ENABLED_ST,
    DISABLE_ST
};

struct State
{
    state_enum myState;

    State(state_enum theState):myState(theState)
    {}

    template <typename... Args>
    /*virtual*/ void operator()(const char * category, Args&&... args) 
    { 
        if(myState == DISABLE_ST)
        {
         // noop    
        }
        else if(myState == ENABLED_ST)
        {

        }
    }

};

static State enabled = State(ENABLED_ST);
static State disabled = State(DISABLE_ST);

struct Monitor
{
    static State* state;

    template <typename... Args>
    static void write(const char * category, Args&&... args)
    {
        state->operator()(category, std::forward<Args>(args)...);
    }
};

State* Monitor::state = &enabled;

【讨论】:

    【解决方案2】:

    您不需要任何“状态”,只需要一个布尔“启用”标志。

    struct Monitor
    {
        static bool enabled;
    
        template <typename... Args>
        static void write(const char * category, Args&&... args)
        {
            if (enabled) {
                do_write(category, std::forward<Args>(args)...);
            }
        }
    
        template <typename... Args>
        static void do_write(const char * category, Args&&... args) { /*processing category and args*/ }
    
    };
    
    bool Monitor::enabled = true;
    

    与虚拟方法方法相比,这节省了一定程度的间接性,并且由于静态分派与单个分支(实际上多个分支都引用同一个变量,尽管仍然比动态调度更适合管道)。

    禁用状态的运行时成本只是一个未采用的分支(以及对 write 本身的调用,它太大而无法内联)。 但是如果要保留在运行时切换状态的能力,则不能消除分支。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-08
      • 2011-06-25
      • 2015-01-04
      • 1970-01-01
      • 1970-01-01
      • 2021-11-08
      • 2023-03-31
      相关资源
      最近更新 更多