基于策略的设计和默认设置

时间:2010-05-25 21:32:27

标签: c++ policy-based-design

很难为这个问题找到一个好头衔。我真正需要的是能够提供具有不同数量的参数的模板参数来代替单个参数。没有多大意义所以我会解释原因:

template < typename T, template <typename,typename> class Policy = default_policy >
struct policy_based : Policy<T, policy_based<T,Policy> >
{
  // inherits R Policy::fun(arg0, arg1, arg2,...,argn)
};

// normal use:
policy_base<type_a> instance;

// abnormal use:
template < typename PolicyBased > // No T since T is always the same when you use this
struct custom_policy {};

policy_base<type_b,custom_policy> instance;

交易是对于许多异常使用,策略将基于单一类型T,并且不能真正在T上参数化,因此将T作为参数是没有意义的。对于其他用途,包括默认值,策略对任何T都有意义。

我有几个想法,但没有一个是真正的最爱。我认为我有一个更好的答案 - 使用组合而不是策略 - 然后我意识到我有这种情况,其中fun()实际上需要类本身不具备的额外信息。

这就像我第三次重构这个愚蠢的构造,我有很多自定义版本,我正在努力巩固。我希望这次得到一些固定的东西,而不仅仅是钓鱼,希望这次有效。所以我现在正在寻找想法,希望有人能拥有一些东西让我印象深刻,我会切换神灵。有人有个好主意吗?

编辑:你可能会问自己为什么我不只是从default_policy模板中的策略定义中检索T.原因是default_policy实际上是专门针对某些类型的T.自从提出问题后,我想出了一些可能是我需要的东西,接下来会有,但我仍然可以使用其他一些想法。

template < typename T >
struct default_policy;

template < typename T, template < typename > class Policy = default_policy >
struct test : Policy<test<T,Policy>>
{};


template < typename T >
struct default_policy< test<T, default_policy> >
{
  void f() {}
};

template < >
struct default_policy< test<int, default_policy> >
{
  void f(int) {}
};

编辑: 仍然搞乱它。我不太喜欢上面的内容,因为它使default_policy永久地与“test”结合,因此无法在其他方法中重复使用,例如下面建议使用多个模板。它也根本没有扩展,并且至少只要“test”具有一个参数列表。尝试了一些失败的方法,直到我找到了另一个看起来有效的方法:

template < typename T >
struct default_policy;

template < typename T, template < typename > class Policy = default_policy >
struct test : Policy<test<T,Policy>>
{};

template < typename PolicyBased >
struct fetch_t;

template < typename PolicyBased, typename T > struct default_policy_base;

template < typename PolicyBased >
struct default_policy : default_policy_base<PolicyBased, typename fetch_t<PolicyBased>::type> {};

template < typename T, template < typename > class Policy >
struct fetch_t< test<T,Policy> > { typedef T type; };

template < typename PolicyBased, typename T >
struct default_policy_base
{
  void f() {}
};

template < typename PolicyBased >
struct default_policy_base<PolicyBased,int>
{
  void f(int) {}
};

2 个答案:

答案 0 :(得分:1)

我遇到了类似的问题,并没有找到理想的答案。据我所知,C ++没有对可变数量的模板参数的优雅支持,所以你必须通过在另一个类中“包装”额外的参数来绕过它;

policy_base< twoArgs<part1, part2> >

你可以通过为twoArgs制作typedef来实现这一点,但在这个基本情况下不是很多。 (请记住,您可以通过在模板化类中使用成员typedef来“执行”模板化的typedef。)

或通过对核心模板进行许多不同的声明,使用不同的args;

template< typename T1 > struct base {...}
template< typename T1, typename t2 > struct base {...}
//etc

答案 1 :(得分:1)

你看过所谓的命名模板参数吗?这允许您有许多具有隐藏默认值的参数,每个参数都可以按名称覆盖(即以任意顺序)。这是依赖多级间接和多重继承的技巧。在Vandevoorde&amp; Sons出版的“模板完整指南”一书的第16.1章中对此进行了描述。约祖蒂斯。有关在线博览会,请参阅here。该想法在Boost.Parameter

中实施

以下是Boost.Parameter库的简短摘要。

步骤1)您通过以下宏声明每个参数par0parN

BOOST_PARAMETER_TEMPLATE_KEYWORD(par0)
BOOST_PARAMETER_TEMPLATE_KEYWORD(par1)
// ... 
BOOST_PARAMETER_TEMPLATE_KEYWORD(parN)    

每个宏都会定义名称空间par0中的常规类tag和名称空间范围内的类模板par0

namespace tag { struct par0; } // keyword tag type
template <class T>
struct par0
: 
    parameter::template_keyword<tag::par0, T>
{};

步骤2)您使用必需和可选参数声明您的班级签名:

using boost::mpl::_;

typedef parameter::parameters<
    parameter::required<tag::par0>
  , parameter::optional<tag::par1>
  // ...
  , parameter::optional<tag::parN>
> your_signature;

步骤3)宣布您的政策类

template <
    class a0
  , class a1 = parameter::void_
  // ...
  , class aN = parameter::void_
>
struct your_policy
{
    // Create ArgumentPack
    typedef typename
      your_signature::bind<a0, a1, /* ... */ ,aN>::type
    args;

    typedef typename parameter::value_type<
      args, tag::par0>::type par0;

    typedef typename parameter::value_type<
      args, tag::par1, your_par1_default>::type par1;

    // ...

    typedef typename parameter::value_type<
      args, tag::parN, your_parN_default>::type parN;
};

步骤4)定义您的政策和专业化

template<typename T>
class default_policy
:
    your_policy<T> // all hidden template parameters equal to their defaults
{};

template<typename T>
class some_par2_specialized_policy
:
    your_policy<T, par2<some_override_for_par2> > // note par1 does not have to be overriden!!
{};

对于灵活且可扩展的基于策略的设计,我的经验是Boost.Parameter就像一个魅力(如果你有超过8个隐藏参数,你可能需要覆盖BOOST_PARAMETER_MAX_ARITY)。

应该可以使您的设计适应这种技术。当然,一旦引入了具有隐藏默认值的额外模板参数,您需要选择覆盖使用策略类的代码的情况。这与使用多个特征将您的专业行为传达给客户端代码时没有什么不同,除了使用策略将所有内容完美地包装在一起。

相关问题