簡體   English   中英

C ++傳遞方法指針作為模板參數

[英]C++ passing method pointer as template argument

我有這樣的調用函數:

template<typename T, void (T::*method)()>
void CallMethod(T *object){
    (object->*method)(args);
}

雖然這完美地運作:

void (*function)(A *) = &CallMethod<A, &A::method>;

這段代碼在第二行沒有編譯錯誤:

void (A::*method)() = &A::method;
void (*function)(A *) = &CallMethod<A, method>;

有什么辦法可以解決嗎? 我需要CallMethod模板來獲取一個指向存儲在變量中的方法的常量指針。

必須在編譯時知道所有模板參數。 因此,如果method實際上是一個變量而不是一個特定的函數,那么就沒有辦法做你想做的事情。

相反,您可以創建一個template struct ,該template struct具有指向成員函數的指針作為成員,並實現一個與CallMethod<A, method>類似的operator()

在這一點上,我已經確定你有一個API,它接受一個函數和一個指針,你需要提供它。 我假設你必須總是提供一個A *指針?

如果它是一個非常通用的回調但必須是一個函數(不能是boost :: function)並且必須是一個指針(可能是void *)那么你需要一個像這樣的函數:

struct GenericHolder
{
   boost::function0<void> func;
};

void GenericCallback( void * p )
{
   GenericHolder * holder = static_cast< GenericHolder * >(p);
   holder->func();
   delete holder;
}

在這種情況下,我在調用時調用delete,所以我假設我們在調用時調用new,即當你構建指針時調用它。 當然,可能不是您傳遞的指針在第一次調用時被刪除,因此適當地管理生命周期。

如果你控制了“另一面”,那么不要按設計做到這一點,但讓那邊持有boost :: function並調用它。

內存管理仍然是您需要處理的問題。 例如,當你調用boost :: bind時,它會為你在幕后的結構中包裝東西。 如果這些是你用new分配的指針,你需要在某個時候刪除它們。 如果它們是引用,它們必須在通話時仍然有效。 指向局部變量的指針也可能是個問題。 shared_ptrs當然是理想的。 如果您經常使用該概念,那么很難找到跟蹤boost :: bind錯誤的錯誤。

看起來您正在嘗試通過模板實現接口。 有可能,但是擁有一個帶虛函數的基類並使用基類指針通過一個簡單的函數調用來訪問虛函數會不會更好?

標題:

class AbstractBase
{
public:
    virtual void func() = 0;
}
class SubClass : public AbstractBase
{
public:
    void func();
}

源文件:

void SubClass::func()
{
    std::cout << "Virtual function called.\n";
}

用法示例:

int main()
{
    AbstractBase* base;
    base = new SubClass();
    base->func(); // virtual function call through base pointer will use SubClass's implementation
    return 0;
}

您可以存儲一個指針向量(如果使用boost或C ++ 0x,則為智能指針),您可以循環使用它來執行各種SubClass相關的操作。

或者,使用boost::functionstd::function (C ++ 0x),它是包含所討論的成員函數的對象,並使用對象實例作為第一個參數將其作為模板參數傳遞。 這歸結為上述的解決方法。

更新 :看到你需要一個簡單的C函數指針,有一些技巧可能會影響c ++ 0x或boost: bindfunction::target等運行時性能......

你需要這個來從std/boost::function獲取一個函數指針,這將把第一個參數綁定到一個對象 bind在運行時動作,所以在這種情況下,模板可能更好......

如果2種方法具有完全相同的簽名怎么辦?

模板無法區分它(它選擇類型,而不是值),因此相同的生成模板函數將調用第一種方法或第二種方法,你會打賭你的手嗎?

您可以使用一些技巧在編譯時使用__LINE__宏創建不同的類型,但它涉及將宏與當前代碼混合,這將很難遵循。 這段代碼:

template<typename T, void (T::*method)(), int>
void CallMethod(T *) { ... }
#define MakeCallMethod(X, Y) &CallMethod<X, X::&Y, __LINE__>

// This will work (it does not without the __LINE__ trick, ptr1 == ptr2 in that case)
typedef void (*ptrFunc)(A *);
ptrFunc ptr1 = MakeCallMethod(A, method);
ptrFunc ptr2 = MakeCallMethod(A, otherMethodWithSameSignature);

Assert(ptr1 != ptr2);

但是,您將無法將指針保存到變量中的方法並從中創建“自動包裝器”。 它現在是運行時,您需要一個運行時解決方案。

首先,請創建typedef http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.5

第二,

void (*function)(A *) = &CallMethod<A, method>;

在這種情況下, method是一個變量,而變量不能是模板參數。 我沒有測試過,但也許你可以試試......

void (*function)(A *) = &CallMethod<A, void (A::*method)()>;

暫無
暫無

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

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