警告:問題を説明するために、先に長い紹介が必要です。VandevoordeとJosuttisの16.1章で最初に説明された名前付きテンプレート引数イディオムは、Boost.Parameterライブラリを使用して簡単に記述できます。
#include <iostream>
#include <typeinfo>
#include <boost/parameter.hpp>
#include <boost/static_assert.hpp>
struct DefaultPolicy1 {};
struct DefaultPolicy2 {};
typedef boost::parameter::void_ DefaultSetter;
BOOST_PARAMETER_TEMPLATE_KEYWORD(Policy1_is)
BOOST_PARAMETER_TEMPLATE_KEYWORD(Policy2_is)
typedef boost::parameter::parameters<
boost::parameter::optional<tag::Policy1_is>,
boost::parameter::optional<tag::Policy2_is>
> PolicySelector;
template
<
class PolicySetter1 = DefaultSetter,
class PolicySetter2 = DefaultSetter
>
class BreadSlicer
{
typedef typename PolicySelector::bind<
PolicySetter1,
PolicySetter2
>::type Policies;
public:
// extract policies:
typedef typename boost::parameter::value_type<
Policies, tag::Policy1_is, DefaultPolicy1
>::type P1;
typedef typename boost::parameter::value_type<
Policies, tag::Policy2_is, DefaultPolicy2
>::type P2;
};
上記のコードを使用すると、のオプションのテンプレートパラメータに名前を付けて任意の順序でオーバーライドできBreadSlicer
ます。これにより、多くのデフォルトパラメータを使用したポリシーベースの設計が非常に便利になります。Policy1_is
Policy2_is
int main()
{
typedef BreadSlicer<> B1;
// can override any default policy
typedef BreadSlicer< Policy1_is<int> > B2;
typedef BreadSlicer< Policy2_is<char> > B3;
// order of policy-setting is irrelevant
typedef BreadSlicer< Policy1_is<int>, Policy2_is<char> > B4;
typedef BreadSlicer< Policy2_is<char>, Policy1_is<int> > B5;
// similar static asserts work for B1 ... B4
BOOST_STATIC_ASSERT((std::is_same<B5::P1, int >::value));
BOOST_STATIC_ASSERT((std::is_same<B5::P2, char>::value));
return 0;
}
ポリシーベースの設計での非常に微妙なODR違反を回避するために(説明については、Alexandrescuによるこの古い投稿を参照してください)、名前付きテンプレート引数にCRTPパターンを適用できるようにしたいと思います。
int main()
{
// ERROR: this code does NOT compile!
struct CuriousBreadSlicer
:
BreadSlicer< Policy1_is<CuriousBreadSlicer> >
{};
typedef CuriousBreadSlicer B6;
BOOST_STATIC_ASSERT((std::is_same<B6::P1, CuriousBreadSlicer>::value));
BOOST_STATIC_ASSERT((std::is_same<B6::P2, DefaultPolicy2 >::value));
return 0;
}
ただし、一部の内部static_assertが(VC10 SP1)のようなメッセージで失敗するため、上記のBoost.Parameter実装はコンパイルに失敗します。
'main :: CuriousBreadSlicer':コンパイラの組み込み型特性'__is_base_of'への引数として未定義のクラスは許可されていません
質問:この静的チェックをオフにすることはできますか?マクロまたはテンプレートのトリックのいずれかを介して?
考えられる回避策について:
- 上記のコードは、この手書きコードと機能的に同等です。そのコードでは、CRTPパターンが機能します。ただし、Boost.Parameterライブラリが便利に自動化する多くの定型コードが必要です。
- CRTPパラメーターを常にテンプレート引数のリストの最初に配置し、
Policy1_is
クラスでラップしないようにすることができます。これにより、コンパイル時のエラーは解決されますが、オーバーライドの順序に依存しなくなります。
ですから、私はゴルフ選手が「クラブの間」と呼んでいるもののようです。どのソリューションが最適ですか?