2016-12-07 94 views
2

我很难理解为什么下面的简单程序不能编译。我有一个variadic模板类(下面的my_type),我想用它来转换一个mpl向量。下面的代码片段导致编译错误“/ boost/mpl /aux_/preprocessed/gcc/apply_wrap.hpp:38:19:'apply'在'template'关键字之后没有引用模板。使用boost mpl lambda与variadic模板类

#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采取一个模板参数正常,但我想明白为什么一个可变版本不起作用。先谢谢你!

回答

0

变换所期望的第二个参数是一个未经过的一元操作。

在你的情况下,my_type不是metafunction mpl预计,因为它正在使用可变参数列表。

A metafunction在最简单的情况下暴露了type typedef或ststic boolvalue。对于如:

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

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

在您的例子my_type纯粹是一个类型,并且不能被用作元函数或操作所要求的transform元函数,其是具有type字段,用于指示变换的类型它不满足metafunction的标准。

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

文档参考: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的专家。

template <class T> 
struct my_type{}; 

但是,这并不与我前面提到的即operation需要type标识符顺利:

按照下面的评论由OP,如果我们改变my_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

运用一些重宏观和模板机械和专业后,上述检查synthesises以下结构:

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执行。

+1

谢谢你的帮助。我的印象是'my_type <_1>'本质上是通过mpl :: lambda转换成一元函数类的。我还不是很清楚,为什么不是这样,因为一个参数传递给'my_type'。你能解释一下为什么'my_type <_1>'不被认为是一个有效的一元元函数类吗? – linuxfever

+0

已更新我的答案。希望现在应该清楚。 – Arunmu

+1

恐怕我不同意“根据转换元函数的要求,它有一个类型字段来表示转换后的类型”。例如,如果将'my_type'更改为'template struct my_type {}',则代码将编译并提供所需的输出,即使'my_type'仍不会显示'type'字段。 – linuxfever