【问题标题】:using boost mpl lambda with variadic template class使用带有可变参数模板类的 boost mpl lambda
【发布时间】:2016-12-07 00:05:01
【问题描述】:

我很难理解为什么以下简单程序无法编译。我有一个可变参数模板类(下面的my_type),我想用它来转换一个 mpl 向量。以下 sn-p 导致编译错误“/boost/mpl/aux_/preprocessed/gcc/apply_wrap.hpp:38:19: 'template' 关键字后面的 'apply' 未引用模板”。

#include <boost/mpl/vector.hpp>
#include <boost/mpl/transform.hpp>

template <class... T>
struct my_type{};

using namespace boost::mpl;

using test_type = vector<int, double>;

// expected result is vector< my_type<int>, my_type<double> >
using result_type = transform< test_type, my_type<_> >::type; 

int main() {

}

使my_type 采用单个模板参数可以正常工作,但我想了解为什么可变参数版本不起作用。提前谢谢!

【问题讨论】:

    标签: c++ boost template-meta-programming variadic boost-mpl


    【解决方案1】:

    transform 期望的第二个参数是一个你没有传递的一元操作。

    在您的情况下,my_type 不是 mpl 所期望的 metafunction,因为它正在使用可变参数列表。

    在最简单的情况下,metafunction 公开了 type 类型定义或 ststic bool value。例如:

    template <typename T>
    struct add_pointer {
        using type = T*;
    };
    

    注意add_pointer 如何转换提供的模板参数。这是unary 操作的示例,因为它只需要一个模板参数T

    在您的示例中,my_type 纯粹是一种类型,不能用作元函数或操作,因为它不符合 transform 元函数所要求的 metafunction 标准,该元函数具有 type 字段表示转换后的类型。

    在某些情况下,简单的模板类型会转换为metafunction,如下面的Detailed Reasoning 部分所述。

    文档参考:http://www.boost.org/doc/libs/1_31_0/libs/mpl/doc/ref/Reference/transform.html

    代码:

    #include <boost/mpl/vector.hpp>
    #include <boost/mpl/transform.hpp>
    #include <boost/mpl/equal.hpp>
    
    #include <type_traits>
    #include <typeindex>
    #include <iostream>
    
    template <class... T>
    struct my_type{};
    
    using namespace boost::mpl;
    
    using test_type = vector<int, double>;
    
    template <typename T>
    struct add_my_type {
        using type = my_type<T>;
    };
    
    using result_type = typename transform< test_type, add_my_type<_1> >::type; 
    
    int main() {
        static_assert (equal<result_type, vector< my_type<int>, my_type<double> >>::value, "Nope!!");
    
        std::cout << typeid(result_type).name() << std::endl; 
    }
    

    LIVE DEMO

    详细原因

    上面解释的原因很简短,应该足以回答这个问题。但是,让我们尽可能深入研究细节。

    免责声明:我不是 boost::mpl 方面的专家。

    根据 OP 下面的评论,如果我们将 my_type 更改为:

    template <class T>
    struct my_type{};
    

    但这与我之前提到的并不顺利,即operation 需要一个type 标识符。那么,让我们看看 mpl 在幕后做了什么:

    struct transform 有点像:

    template<  
      typename Seq1 = mpl::na
    , typename Seq2OrOperation = mpl::na      
    , typename OperationOrInserter = mpl::na          
    , typename Inserter = mpl::na             
    >
    struct transform {
      boost::mpl::eval_if<
            boost::mpl::or_<
                boost::mpl::is_na<OperationOrInserter>, 
                boost::mpl::is_lambda_expression<my_type<mpl_::arg<1> > >,
                boost::mpl::not_<boost::mpl::is_sequence<my_type<mpl_::arg<1> > > >,
                mpl_::bool_<false>, 
                mpl_::bool_<false> 
            >,
            boost::mpl::transform1<
                boost::mpl::vector<int, double>, 
                my_type<mpl_::arg<1>>, 
                mpl_::na
            >, 
            boost::mpl::transform2<boost::mpl::vector<int, double>,
                my_type<mpl_::arg<1> >, 
                mpl_::na, mpl_::na> 
            >
    
    };
    

    看这里的重要部分是is_lambda_expression 元函数,它基本上检查您的Operation 是否满足metafunction 的要求。

    在应用了一些繁重的宏和模板机制和特化之后,上面的检查合成了下面的结构:

    template<
          typename IsLE, typename Tag
        , template< typename P1 > class F
        , typename L1
        >
    struct le_result1
    {
        typedef F<
              typename L1::type
            > result_;
    
        typedef result_ type;
    };
    

    这里,F 是您的 my_typeL1placeholder。所以,本质上,上面的结构只不过是add_my_type,我在最初的回复中已经展示了它。

    如果到目前为止我是正确的,le_result1operation,它将在您的 sequence 上执行。

    【讨论】:

    • 感谢您的帮助。我的印象是my_type&lt;_1&gt; 本质上后来通过 mpl::lambda 转换为一元元函数类。我仍然不太清楚为什么不是这种情况,因为单个参数被传递给my_type。您能否解释一下为什么my_type&lt;_1&gt; 不被视为有效的一元元函数类?
    • 已更新我的答案。希望现在应该清楚了。
    • 恐怕我不同意“按照转换元函数的要求,它有一个类型字段来指示转换后的类型”。例如,如果您将my_type 更改为template &lt;class T&gt; struct my_type{} ,代码将编译并提供所需的输出,即使my_type 仍然没有公开type 字段。
    • 或者换一种说法,即使我在可变参数my_type 中添加了type 字段,代码仍然无法编译。
    • @linuxfever Hmm..so you want me to do the hard work :) 接受挑战。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-12
    • 2014-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多