簡體   English   中英

派生類使用模板沒有開銷?

[英]Derived Class with no overhead using templates?

我想完成以下事項:

  1. 賓語。
  2. 調試對象版本,在函數中具有額外功能以進行跟蹤。

現在,我目前有一個使用宏的編譯時解決方案,如果沒有使用正確的標志編譯庫,則解析為do {} while(0)

我想將此功能轉移到在運行時啟用。 做這個的最好方式是什么?

我想這樣做: Base * obj = (isGlobalDebugEnabled) ? new Debug(...) : new Base(...); Base * obj = (isGlobalDebugEnabled) ? new Debug(...) : new Base(...); 類型的東西。 我是不是想要這樣的東西?

注意,標准虛函數並不能真正解決問題,因為每個函數都必須在對象的派生(調試)版本中復制,從而破壞了目的。

此外,最低級別的功能是非常高的音量(配置文件時大於6000億次調用)所以我想為“基類”編譯一個編譯的零開銷解決方案。 當然,Debug對象可能更慢。

這就是我想到模板的原因。 注意:除了VS2010功能(基本lambda等)之外,我沒有C ++ 11 / boost訪問權限 我能做點什么嗎

template <bool debug = false>
class Object {
    std::enable_if<debug> void printTrace(); // Add functions based on debug/not
};
void Object::doSomething(...){
    <only do this if debug without runtime check> addToTrace(...);
    doTheStuff();
}

我看到這個鏈接指向我偽造的繼承與模板方向,如果這有幫助。

謝謝您的幫助

AK

編輯:我剛剛意識到我可能會采用錯誤的方式 - 可能將Debug對象作為基類,並在Regular對象中使用no-ops覆蓋功能。 這似乎是一種更好的方式。 但是,由於這些高性能要求,我仍然希望避免vtable跳轉,所以我猜我的模板問題仍然存在? 也許?

編輯2:正如KerrickSB所指出的,使用的一個例子可能更清楚:

主要代碼:

void ComputeSomething() {
    Object * obj = (globalDebugFlag) ? new DebugObject(...) : new Object(...);
    obj->insertElement(elem); // Inserts in Object, Inserts and traces actions in DebugObject
    ...
}

其中Object當前是一個單獨的DLL,其中globalDebugFlag是一個(建議的)全局變量,由一個命令設置,該命令來自一個單獨的端口,而不是導致調用ComputeSomething()的端口。

我計划使用全局跟蹤變量,然后通過端口(通過處理此端口的全局對象)將跟蹤推回,以便在前端工具上顯示。

根據定義,運行時決策意味着您在運行時完成所有成本的決策,而不是編譯時間。 你不會因此而僥幸逃脫。

但是,您可以將檢查推送到調用堆棧,直到它們不經常發生以滿足您的需求為止。當然,更改調試標志的效果會稍微延遲(多少取決於您忽略的檢查)。 使用模板,您可以復制/專門化代碼以進行調試和非調試版本,而無需復制源代碼。

template <bool debug>
class Object {
  void something() {
    // branch on compile-time constant - can be optimized
    if (!debug) return;
    // ...
  }
}

template<bool debug>
useObject(Object<debug> o) {
    for(int i = 0; i < 10000; ++i) {
        // statically calls specialized implementation
        o.something();
    }
}

debugEnabled ? useObject(Object<true>()) : useObject(Object<false>());

這是一個非常基本的想法。 我不確定它是否會推廣或擴展,但我們可以討論。

static bool debug_mode = /* ... */;    // global

class Container
{
    struct ContainerImpl
    {
        virtual ~ContainerImpl() { }
        virtual void insert(int) = 0;
        std::unique_ptr<ContainerImpl> clone() const = 0;
    };

    std::unique_ptr<ContainerImpl> impl;
public:
    Container()
    : impl(debug_mode ? new DebugImpl : new MainImpl)
    { }

    Container(Container const & rhs)
    : impl(rhs.impl->clone())
    { }

    Container(Container && rhs) noexcept
    : impl(std::move(rhs.impl))
    { }

    // also implement assignment


    /*** Main interface ***/

    void insert(int x)
    {
        impl->insert(x);
    }


    /*** Implementations ***/

    struct MainImpl : ContainerImpl { /* main implementation */ };

    struct DebugImpl : MainImpl  // just for example
    {
        virtual void insert(int x)
        {
            // trace insertion
            MainImpl::insert(x);
        }

        std::unique_ptr<ContainerImpl> clone() const
        {
            return { new DebugImpl(*this); }
        }
    };
};

現在,您可以將Container用作普通的值類型對象,並且它將在內部根據標志使用不同的實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM