2014-12-05 46 views
4

目前,我有以下代碼:方式概括C++代碼與不同類型相似

static void markPoolsFree(const TNetgroupPools &group_info, TObjectID netiface) { 
    for (size_t i = 0; i<group_info.public_pools.length();i ++) { 
     SDK::revokeIPPoolFromNetworkInterface(group_info.public_pools[i],netiface); 
    } 

    for (size_t i =0 ; i<group_info.private_pool.length(); i++) { 
     SDK::revokeIPPoolFromNetworkInterface(group_info.private_pool[i].pool_id, 
               netiface); 
    } 
} 

具有基本相同的邏輯,但在類型group_info.public_pools[i]group_info.private_pool[i]型動物,這就是爲什麼在第二循環中,我們必須添加.pool_id成員電話。這些類型是不同的,並沒有任何關係。

我想重寫這段代碼,使其更廣泛一點,比如像這樣(素描):

// template function 
template <typename Container, typename PredArgs> 
static void revokeIPPool(const Container &pool, TObjectID netiface, 
         bool (*pred)(PredArgs pool_id, PredArgs netiface_id)) 
{ 
    for (size_t i = 0; i < pool.length(); ++i) { 
     if (pred(pool[i], netiface)) { 
      SDK::revokeIPPoolFromNetworkInterface(pool[i], netiface); 
     } 

    } 
} 

// calling code 
static void markPoolsFree(const TNetgroupPools &group_info, TObjectID netiface) { 
    revokeIPPool(group_info.public_pools, netiface, SDK::isPredicateTrue); 
    revokeIPPool(group_info.private_pool, netiface, SDK::isPredicateTrue); 
} 

但問題是,在不同類型public_poolsprivate_pool

問題: 你能給出所有的方法怎麼可能推廣這個代碼的例子嗎?我需要C++ 03代碼,但是C++ 11/C++ 14是可以接受的。

我的想法:

  1. 而不是SDK::revokeIPPoolFromNetworkInterface使wrapperIPPool與重載兩種類型,並調用SDK::revokeIPPoolFromNetworkInterface內部。
  2. 超載revokeIPPool兩種類型(但它的代碼重複,對原來的代碼沒有改善)
  3. 部分函數模板專業化的revokeIPPool(這可能嗎?)
  4. 全功能模板專業化爲revokeIPPool
  5. 裹功能revokeIPPool在課堂上做出部分課堂模板專業化。

問題:

  1. 至極的我的想法是正確的?
  2. 優點和缺點是什麼?
  3. 哪個更適合C++ 03或C++ 11?
  4. 是否有其他解決方案?
+0

私有池的'.pool_id'與'public_pool'類型相同。重載公共池上的函數,返回輸入,並在私有池上返回'.pool_id'。這可以讓你一半。 – Yakk 2014-12-06 02:20:17

回答

2

說不上如果通用的lambda(C++ 14)是可接受的解決方案爲您:

auto revoke_pool = [](auto &pool, TObjectID netiface, auto extract_item) 
{ 
    for(std::size_t i = 0; i < pool.length(); ++i) 
     SDK::revokeIPPoolFromNetworkInterface(extract_item(pool, i), netiface); 
}; 

然後,你只HACE定義的λ來訪問存儲區項目。

revoke_pool(group_info.public_pools, netiface, [](auto &pool, std::size_t idx) { return pool[idx]; }); 
revoke_pool(group_info.private_pool, netiface, [](auto &pool, std::size_t idx) { return pool[idx].pool_id; }); 
2

當我們從C++ 03到C++ 11到C++ 14去了,我們的解決方案變短都在被總代碼少條款和在能夠更加本地化方面 - 無論是明確的勝利。在C++ 14中,我們只需要一個10行函數即可完成,而在C++ 03中,我們需要4個函數。下面是我會怎麼做它在三個功能集:


C++ 03:函子!基本上你應該如何在當天使用每種標準算法(或免費功能)。

template <typename POOL, typename EXTRACTOR> 
static void markPoolsFreeImpl(const POOL &pool, TObjectID netiface, 
    EXTRACTOR ex) 
{ 
    for (std::size_t i = 0; i < pool.length(); ++i) { 
     SDK::removeIPPoolFromNetworkInterface(ex(pool[i]), netiface); 
    } 
} 


static void markPoolsFree(const TNetgroupPools &group_info, TObjectID netiface) { 
    markPoolsFreeImpl(group_info.public_pools, 
        netiface, 
        PublicExtractor()); 

    markPoolsFreeImpl(group_info.private_pools, 
        netiface, 
        PrivateExtractor()); 
} 

// fill in T, U, V as appropriate here, I dunno what they are 
struct PublicExtractor { 
    T operator()(const U& item) const { return item; } 
}; 

struct PrivateExtractor { 
    T operator()(const V& item) const { return item.pool_id; } 
}; 

這也可能是這樣的:

T PublicExtractor(const U& item) { return item; } 

而只是通過它沒有額外的()秒。如果我們意外地提供了markPoolsFreeImplEXTRACTOR而且它們的錯誤代碼是operator(),它只是不會編譯指向它被調用的行。這並不是很好,但它和我們能做的一樣好。


C++ 11:Lambda表達式!該markPoolsFreeImpl功能看起來是一樣的,它只是不是定義我們的仿函數的地方,我們可以內嵌definte他們:

static void markPoolsFree(const TNetgroupPools &group_info, TObjectID netiface) { 
    markPoolsFreeImpl(group_info.public_pools, 
        netiface, 
        [](const U& item) { return item; }); 

    markPoolsFreeImpl(group_info.private_pools, 
        netiface, 
        [](const V& item) { return item.pool_id; }); 
} 

此外,我們可以讓我們的錯誤信息更清晰的情況下,我們通過一種錯誤的提取功能(再次,填寫T適當時):

template <typename POOL, typename EXTRACTOR> 
static void markPoolsFreeImpl(const POOL &pool, TObjectID netiface, 
    EXTRACTOR ex) 
{ 
    static_assert(std::is_same<T, decltype(ex(pool[0]))>::value, 
        "invalid EXTRACTOR: must return a T"); 

    for (std::size_t i = 0; i < pool.length(); ++i) { 
     SDK::removeIPPoolFromNetworkInterface(ex(pool[i]), netiface); 
    } 
} 

C++ 14:簡單lambda表達式!我們甚至沒有標識UV

static void markPoolsFree(const TNetgroupPools &group_info, TObjectID netiface) { 
    markPoolsFreeImpl(group_info.public_pools, 
        netiface, 
        [](const auto& item) { return item; }); 

    markPoolsFreeImpl(group_info.private_pools, 
        netiface, 
        [](const auto& item) { return item.pool_id; }); 
} 

,甚至可以把markPoolsFreeImpl到本地拉姆達:

static void markPoolsFree(const TNetgroupPools &group_info, TObjectID netiface) { 
    // netiface is captured 
    auto impl = [&](const auto& pool, auto ex) { 
     static_assert(std::is_same<T, decltype(ex(pool[0]))>::value, ""); 

     for (std::size_t i = 0; i < pool.length(); ++i) { 
      SDK::removeIPPoolFromNetworkInterface(ex(pool[i]), netiface); 
     } 
    }); 

    impl(group_info.public_pools, [](const auto& item) { return item; }); 
    impl(group_info.private_pools, [](const auto& item) { return item.pool_id; }); 
} 
3

在C++ 03我會使用模板特上特質類。 (通過traits類的主要原因,而不是使用直接功能專業化或重載的原因是您可以對類進行部分模板專業化,但不能使用函數 - 雖然在此不需要它,但可能稍後有用)

static void markPoolsFree(const TNetgroupPools &group_info, TObjectID netiface) { 
    markPoolsFreeImpl(group_info.public_pools, netiface); 
    markPoolsFreeImpl(group_info.private_pools, netiface); 
} 

template<typename T> 
static void markPoolsFreeImpl(POOLS pools, TObjectID netiface) { 
    for (size_t i = 0; i<pools.length();i ++) { 
     PoolId poolid = PoolListTrait<POOLS>::get(pools,i); 
     SDK::revokeIPPoolFromNetworkInterface(poolid,netiface); 
    } 
} 

template<typename T> class PoolListTrait {}; 

template<> class PoolListTrait<PublicPoolList> { 
    static PoolId get(PublicPoolList pools, int i) { return pools[i]; } 
} 

template<> class PoolListTrait<PrivatePoolList> { 
    static PoolId get(PrivatePoolList pools, int i) { return pools[i].pool_id; } 
} 
相關問題