繁体   English   中英

Boost.Parameter:与CRTP结合使用的命名模板参数

[英]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_isPolicy2_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'的参数

问题 :可以关闭此静态检查吗? 通过宏还是模板技巧?

关于可能的解决方法:

  1. 上面的代码在功能上等效于该手写代码 对于该代码,CRTP模式确实有效。 但是,Boost.Parameter库需要大量的样板代码来方便地实现自动化。
  2. 我可能要求CRTP参数始终始终在模板参数列表中,而不是将其包装在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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM