4

この質問に適切なタイトルを思いつくのは難しいです。私が本当に必要としているのは、1 つのパラメーターの代わりに異なる数の引数をテンプレート パラメーターに提供できるようにすることです。あまり意味がないので、理由を説明します。

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;

多くの異常な使用では、ポリシーは 1 つの型 T に基づいており、実際には T でパラメーター化できないため、T をパラメーターとして使用しても意味がありません。デフォルトを含む他の用途では、ポリシーは任意の T で意味をなすことができます。

いくつかのアイデアがありますが、どれも本当にお気に入りではありません。ポリシーの代わりにコンポジションを使用して、より良い答えがあると思いましたが、fun() が実際にはクラス自体にはない追加情報を必要とするこのケースがあることに気付きました。

このばかげた構造をリファクタリングしたのはこれで 3 回目で、統合しようとしているカスタム バージョンがかなりあります。今回は釣りをするだけでなく、何かを突き止めて、今回はうまくいくことを願っています。だから私はちょうど今、誰かが私が神を変えるほど感銘を受ける何かを持っていることを期待してアイデアを釣り上げています. 誰でも良いアイデアがありますか?

編集: 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

いわゆる名前付きテンプレート パラメータを見たことがありますか? これにより、非表示のデフォルトを持つ多くのパラメーターを使用できます。それぞれのパラメーターは、名前で (つまり、任意の順序で) 上書きできます。これは、複数レベルの間接化と多重継承に依存するトリックです。これについては、Vandevorde & Josuttis による書籍「Templates the Complete Guide」の 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 が魅力的に機能します (BOOST_PARAMETER_MAX_ARITYただし、8 つ以上の非表示パラメーターがある場合はオーバーライドする必要があるかもしれません)。

あなたのデザインをこのテクニックに適応させることができるはずです。もちろん、非表示のデフォルトを持つ追加のテンプレート パラメーターを導入したら、ポリシー クラスを使用するコードをオーバーライドするケースを取り除く必要があります。これは、複数のトレイトを使用して特殊な動作をクライアント コードに伝える場合と同じですが、ポリシーを使用すると、すべてがうまくまとめられます。

于 2012-05-31T19:14:01.547 に答える
1

同様の問題がありましたが、望ましい答えが見つかりませんでした。私が知る限り、C++ には可変量のテンプレート引数に対するエレガントなサポートがないため、別のクラスで余分な引数を「ラップ」することで回避する必要があります。

policy_base< twoArgs<part1, part2> >

のtypedefを作成することで、これを少しきれいにすることができますがtwoArgs、この基本的なケースではそれほど多くはありません。(テンプレート化されたクラスでメンバ typedef を使用することにより、テンプレート化された typedef を「実行」できることに注意してください。)

または、コアテンプレートのさまざまな宣言をさまざまな引数で行うことによって。

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