警告:提前说明需要解释问题。在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的旧post),我希望能够在命名模板参数上应用CRTP模式:< / p>
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;
}
但是,上面的Boost.Parameter实现无法编译,因为某些内部static_assert失败并显示消息,如(VC10 SP1)
'main :: CuriousBreadSlicer':不允许使用未定义的类作为 编译器内在类型特征'__is_base_of'
的参数
问题:可以关闭此静态检查吗?通过宏或模板技巧?
关于可能的解决方法:
Policy1_is
类中。这解决了
编译时错误,但它失去了覆盖的顺序独立性。所以看起来我是高尔夫球员所说的“俱乐部之间”。哪种解决方案最好?
答案 0 :(得分:1)
没有CRTP的最小示例:
#include <boost/parameter.hpp>
#include <boost/static_assert.hpp>
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;
struct foo {};
struct bar {};
struct baz;
typedef typename PolicySelector::bind<foo, baz>::type Policies;
boost::parameter::value_type<Policies, tag::Policy1_is, bar>::type x; // <- !!!
因此boost::parameter::value_type
要求策略选择器基于完整类型,而手写类则不然。
我不完全确定为什么一个班级需要自己作为自己的政策。如果你需要,也许你可以用一个完整的东西包装一个不完整的类型:
struct CuriousBreadSlicer : BreadSlicer <
Policy1_is<CuriousBreadSlicer *> > // <- compiles
或者,您可以使用自己的wrap_incomplete_type<>
模板。
当您使用该策略时,您可以检查它是否已包装,并将其解包。