簡體   English   中英

功能模板編程而不是繼承

[英]Functional template programming instead of inheritance

我目前正在研究C ++ 11中的一段代碼:

class A {
public:
    //.. generic public methods which call updateInternalState from time to time ..
private:
    void updateInternalState();
    B internalState;
};

現在我想要有幾個版本的A類,它們都是相同的,除了updateInternalState()方法,它是變化的,至少有3個不同的版本,做不同的事情,將來可能會有更多。 這聽起來幾乎是一個使用基類繼承的好地方,但我想知道是否有一個模板元編程版本,例如:

#include <functional>
template <std::function<void()> updateInternalState>
class A {
public:
//.. generic public methods, which call updateInternalState from time to time ..
private:
    B internalState;

然后我只需要在其他地方定義函數並顯式實例化我想要的A版本。

我認為最大的問題是updateInternalState函數需要訪問A的私有成員。我認為這可以通過將其聲明為A的朋友,或者通過存儲類型為std :: function的成員並分配它的模板參數。

有沒有人有這種方法和任何建議的經驗? 這是一個可怕的想法,我應該回到繼承(我真的不想要,因為項目的其余部分是用通用編程范例編寫的。)

如果update函數只使用internalState ,則可以簡單地將std::function<void(B&)>為成員,在構造期間傳遞:

class A
{
public:
  template <typename F>
  A(F&& func)
  : updateFunc(std::forward<F>(func))

  void doSomething()
  {
    updateFunc(internalState);
  }

private:
  using UpdateFunc = std::function<void(B&)>;
  B internalState;
  UpdateFunc updateFunc;
};

使用此方法,您可以在保持單一類型而不是整個層次結構的同時實現良好的靈活性。

基於模板的解決方案在這里可能不是一個好主意 - 您只需要自定義單個函數 ,但是將其作為類模板將導致為用作參數的每個不同函數生成整個類。 唯一的優點是你可以專門化(或部分專門化)邏輯,但聽起來你並不需要它。

使用繼承或存儲更新功能作為成員。

這將是一個完整的學術答案:-)

第一句話:你想做什么根本沒有意義!

一步步:

您可以使用函數指針作為模板參數:

using FUNCPTR_T = void(*)();


template <  FUNCPTR_T f >
class A {
public:
    void DoSomething()
    {
        (*f)();
    }
};

void f1() { std::cout << "f1" << std::endl; }
void f2() { std::cout << "f2" << std::endl; }

int main()
{
    A<f1> a1;
    A<f2> a2;

    a1.DoSomething();
    a2.DoSomething();
 }

但是如果你想將一個參數傳遞給你的函數,這是一個類指針(this),你需要定義一個函數指針,它代表如下:

using FUNCPTR_T = void(*)(!!!POINTER_TO_THE_CLASS!!!);

但是這個類本身是一個模板,它接受一個函數的指針,該函數有一個參數,該參數是一個指向函數的類的指針.... //無限遞歸!

因此,您的嘗試只是失敗,因為您無法為模板參數指定正確的類型。

正如已經提到的:繼承更容易,也很完美。 使用CRTP通常用於訪問using類。 使用std::function要容易得多,但是將成本轉移到運行時。

你可以存儲一個std::function並使用lambdas:看看這個簡單的類及其用作例子:

#include <functional>
#include <iostream>
#include <conio.h> // for _getch()

class A {
private:
    int _state;
    std::function<int()> _updater;
public:
    A() : _state( 0 ) {}

    void addUpdater( std::function<int()> updater ) {
        _updater = updater;
    }

    void callUpdater() {
        updateInternalState();
    }

    int returnState() const {
        return _state;
    }

private:
    void updateInternalState() {
        _state = _updater();
    }
};

int main() {
    A a;
    a.addUpdater( []() { return 5; } );
    a.callUpdater();
    std::cout << a.returnState() << std::endl;
    a.addUpdater( []() { return 10; } );
    a.callUpdater();
    std::cout << a.returnState() << std::endl;

    _getch();
    return 0;
}

然后,為了跟蹤同一個類的不同實例,而不是繼承,您可以使用map <id, this*> ,其中id可以是int或字符串。 也可以輕松查找。 我認為在這種情況下這可能比模板更好,因為如果你模擬這個只有function不同的類,它將為每個函數更改生成一個全新的類。 是的,由於std::function ,它確實將事物移動到運行時,但實現和管理似乎更簡單。

暫無
暫無

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

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