gpt4 book ai didi

c++ - 升压参数 : named template argument in combination with CRTP

转载 作者:太空宇宙 更新时间:2023-11-04 12:07:51 24 4
gpt4 key购买 nike

警告:前面较长的介绍需要解释问题。在 Vandevoorde 和 Josuttis 的 ch 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_isPolicy2_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 模式:

    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' : an undefined class is not allowed as an argument to compiler intrinsic type trait '__is_base_of'

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

关于可能的解决方法:

  1. 以上代码在功能上等同于this handwrittencode .对于该代码,CRTP 模式确实有效。然而,它需要大量 Boost.Parameter 库如此方便的样板代码自动化。
  2. 我可以要求 CRTP 参数始终位于模板列表的第一位参数而不是将其包装在 Policy1_is 类中。这解决了编译时错误,但它失去了覆盖的顺序独立性。

看来我就是高尔夫球手口中的“in between clubs”。哪种解决方案最好?

最佳答案

没有 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<>模板,为清楚起见。

当您使用该策略时,您可以检查它是否被包装,并解开它。

关于c++ - 升压参数 : named template argument in combination with CRTP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11251242/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com