4

很难为这个问题想出一个好的标题。我真正需要的是能够提供具有不同数量参数的模板参数来代替单个参数。没有多大意义,所以我将讨论原因:

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;

问题是,对于许多异常使用,Policy 将基于一个单一的类型 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”永久结合,因此不能在其他方法中重用,例如下面建议的多个模板。它也根本无法扩展,并且至少与“测试”一样需要一个参数列表。尝试了几种不同的方法,但都失败了,直到我找到了另一种到目前为止似乎有效的方法:

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

2 回答 2

1

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

policy_base< twoArgs<part1, part2> >

您可以通过为 制作 typedef 来稍微修饰一下twoArgs,但在这个基本情况下不会很多。(请记住,您可以通过在模板化类中使用成员 typedefs 来“执行”模板化 typedefs。)

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

template< typename T1 > struct base {...}
template< typename T1, typename t2 > struct base {...}
//etc
于 2010-05-25T21:51:27.883 回答
1

你看过所谓的命名模板参数吗?这允许您拥有许多具有隐藏默认值的参数,每个参数都可以按名称覆盖(即以任意顺序)。这是一个依赖于多层间接和多重继承的技巧。Vandevoorde & Josuttis 所著的“模板完整指南”一书的第 16.1 章对此进行了描述。有关在线展览,请参见此处。这个想法在Boost.Parameter中实现

这是 Boost.Parameter 库的简短摘要。

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

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

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

于 2012-05-31T19:14:01.547 回答