[英]Boost.Parameter: named template argument in combination with CRTP
警告 :前面需要冗长的介绍来解释问题。 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;
};
上面的代码允许通过将它们Policy1_is
命名为Policy1_is
和Policy2_is
BreadSlicer
以任意顺序覆盖BreadSlicer
的可选模板参数。 这使得使用许多默认参数进行基于策略的设计非常方便。
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;
}
但是,上面的Boost.Parameter实现无法编译,因为某些内部static_assert失败并显示类似(VC10 SP1)的消息
'main :: CuriousBreadSlicer':不允许将未定义的类用作编译器固有类型特征'__is_base_of'的参数
问题 :可以关闭此静态检查吗? 通过宏还是模板技巧?
关于可能的解决方法:
Policy1_is
类中。 这解决了编译时错误,但失去了覆盖的顺序独立性。 因此,似乎我是高尔夫球员所说的“在两家具乐部之间”。 哪种解决方案是最好的?
没有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<>
模板。
使用该策略时,可以检查它是否已包装,然后将其展开。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.