如何使用不同的类似类型来概括C ++代码

时间:2014-12-05 20:45:10

标签: c++ templates c++11 c++14

目前我有以下代码:

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. 的完整功能模板专精
  6. 在类中包装函数revokeIPPool并进行部分类模板特化。
  7. 问题:

    1. 我的想法是对的吗?
    2. 优点和缺点是什么?
    3. 哪个更习惯于C ++ 03或C ++ 11?
    4. 还有其他解决方案吗?

3 个答案:

答案 0 :(得分:3)

在C ++ 03中,我在traits类上使用模板特化。 (通过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; }
}

答案 1 :(得分:2)

Dunno如果通用lambdas(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);
};

然后你只需要定义一个lambda来访问池项目。

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 :(得分:2)

当我们从C ++ 03到C ++ 11再到C ++ 14时,我们的解决方案在总代码减少和能够更加本地化方面都变得更短 - 两者都是明显的胜利。在C ++ 14中,我们只能在一个10行函数中完成它,而在C ++ 03中我们需要4个函数。以下是我将如何在三个功能集中执行此操作:


C ++ 03: Functors !基本上你应该如何在一天中使用每个标准算法(或自由函数)。

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; }

然后在没有额外()的情况下传递它。如果我们意外地向markPoolsFreeImpl EXTRACTOR提供了错误的operator(),那么它就不会编译指向它所调用的行。这不是很好,但它和我们能做的一样好。


C ++ 11: Lambdas markPoolsFreeImpl函数看起来可能相同,只是不管在哪里定义我们的仿函数,我们都可以内联它们:

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:更简单的Lambdas !我们甚至不需要识别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变成当地的lambda:

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; });
}