使用 boost::mpl::for_each 类型包装器错误(Abrahams & Gurtovoy 书中的第 9.1.1 节)
以下代码几乎是从 David Abrahams 和 Beyond 所著的《C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond》一书的第 9.1.1 节中逐字复制的。阿列克谢·古尔托沃伊。
唯一的变化是我希望能够使用常规 Boost 模板 mpl::identity 更改书中的类型包装模板。但是,在 Microsoft Visual C++ Express 2010 (SP1) 下,如果我这样做,我会收到一个神秘的编译器警告。
这似乎与类型包装模板有一个名为“type”的内部 typedef 这一事实有关。将该 typedef 更改为“Type”(或简单地删除该行)将使代码正常工作。有人对这种奇怪的行为有解释吗?
#include <iostream>
#include <typeinfo>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/vector.hpp>
namespace mpl = boost::mpl;
// added a nested typedef named "type" is equivalent to mpl::identity
template <class T>
struct wrap
{
// changing type -> Type or removing this line
// makes the code compile and produce correct output!
typedef T type;
};
struct print_type
{
template <class T>
void operator() (wrap<T>) const
{
std::cout << typeid(T).name() << std::endl;
}
};
class A
{
A() {} // private constructor
};
class B
{
B() {} // private constructor
};
typedef boost::mpl::vector<A,B> AB;
int main()
{
boost::mpl::for_each<AB, wrap<mpl::_> >(
print_type()
);
/* Output:
class A
class B
*/
return 0;
}
/I"C:\Program Files\boost\boost_1_47" /I"C:\Program Files\boost" /Zi /nologo /W3 /WX- /O2 /Oi /Oy- /GL /D 的输出WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm- /EHsc /GS /Gy /fp:精确 /Zc:wchar_t /Zc:forScope /Fp"Release\mpl.pch" /Fa"Release\" /Fo"Release\" /Fd"Release\vc100.pdb" /Gd /analyze- /errorReport:队列
:
1>------ Build started: Project: mpl, Configuration: Release Win32 ------
1> main.cpp
1>C:\Program Files\boost\boost_1_47\boost/mpl/for_each.hpp(75): error C2784: 'void print_type::operator ()(wrap<T>) const' : could not deduce template argument for 'wrap<T>' from 'arg'
1> ..\..\..\mpl\main.cpp(20) : see declaration of 'print_type::operator ()'
1> C:\Program Files\boost\boost_1_47\boost/mpl/for_each.hpp(101) : see reference to function template instantiation 'void boost::mpl::aux::for_each_impl<false>::execute<first,last,TransformOp,F>(Iterator *,LastIterator *,TransformFunc *,F)' being compiled
1> with
1> [
1> TransformOp=wrap<boost::mpl::_>,
1> F=print_type,
1> Iterator=first,
1> LastIterator=last,
1> TransformFunc=wrap<boost::mpl::_>
1> ]
1> ..\..\..\mpl\main.cpp(42) : see reference to function template instantiation 'void boost::mpl::for_each<AB,wrap<T>,print_type>(F,Sequence *,TransformOp *)' being compiled
1> with
1> [
1> T=boost::mpl::_,
1> F=print_type,
1> Sequence=AB,
1> TransformOp=wrap<boost::mpl::_>
1> ]
========== Build: 0 succeeded, 1 failed, 2 up-to-date, 0 skipped ==========
The following code is copied almost verbatim from section 9.1.1 of the book C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond by David Abrahams & Aleksey Gurtovoy.
The only change is that I want to be able to change the type wrapper template from the book with the regular Boost template mpl::identity. However, under Microsoft Visual C++ Express 2010 (SP1) I get a mysterious compiler warning if I do that.
It seems somehow related to the fact that the type wrapper template has an inner typedef named "type". Changing that typedef to "Type" (or simply removing that line) will make the code work correctly. Does anyone have an explanation for this weird behavior?
#include <iostream>
#include <typeinfo>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/vector.hpp>
namespace mpl = boost::mpl;
// added a nested typedef named "type" is equivalent to mpl::identity
template <class T>
struct wrap
{
// changing type -> Type or removing this line
// makes the code compile and produce correct output!
typedef T type;
};
struct print_type
{
template <class T>
void operator() (wrap<T>) const
{
std::cout << typeid(T).name() << std::endl;
}
};
class A
{
A() {} // private constructor
};
class B
{
B() {} // private constructor
};
typedef boost::mpl::vector<A,B> AB;
int main()
{
boost::mpl::for_each<AB, wrap<mpl::_> >(
print_type()
);
/* Output:
class A
class B
*/
return 0;
}
Output of /I"C:\Program Files\boost\boost_1_47" /I"C:\Program Files\boost" /Zi /nologo /W3 /WX- /O2 /Oi /Oy- /GL /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm- /EHsc /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Fp"Release\mpl.pch" /Fa"Release\" /Fo"Release\" /Fd"Release\vc100.pdb" /Gd /analyze- /errorReport:queue
:
1>------ Build started: Project: mpl, Configuration: Release Win32 ------
1> main.cpp
1>C:\Program Files\boost\boost_1_47\boost/mpl/for_each.hpp(75): error C2784: 'void print_type::operator ()(wrap<T>) const' : could not deduce template argument for 'wrap<T>' from 'arg'
1> ..\..\..\mpl\main.cpp(20) : see declaration of 'print_type::operator ()'
1> C:\Program Files\boost\boost_1_47\boost/mpl/for_each.hpp(101) : see reference to function template instantiation 'void boost::mpl::aux::for_each_impl<false>::execute<first,last,TransformOp,F>(Iterator *,LastIterator *,TransformFunc *,F)' being compiled
1> with
1> [
1> TransformOp=wrap<boost::mpl::_>,
1> F=print_type,
1> Iterator=first,
1> LastIterator=last,
1> TransformFunc=wrap<boost::mpl::_>
1> ]
1> ..\..\..\mpl\main.cpp(42) : see reference to function template instantiation 'void boost::mpl::for_each<AB,wrap<T>,print_type>(F,Sequence *,TransformOp *)' being compiled
1> with
1> [
1> T=boost::mpl::_,
1> F=print_type,
1> Sequence=AB,
1> TransformOp=wrap<boost::mpl::_>
1> ]
========== Build: 0 succeeded, 1 failed, 2 up-to-date, 0 skipped ==========
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
一些术语,摘自 Boost.MPL 参考手册
type
的嵌套类型的类型apply
的嵌套元函数的类型因此我们知道
wrap<>
是一个元函数,并且wrap
既是占位符表达式又是元函数。当为
TransformOp
模板参数传递mpl::for_each<>
元函数或元函数类时,它会评估该元函数/元函数类以获得转换结果。因此,如果您想要传递原始占位符表达式而不进行进一步计算,则您的占位符表达式不得满足元函数或元函数类的条件。在您的场景中,因为
wrap<>
是 一个元函数,mpl::for_each<>
正在评估它并生成A
和B
作为转换后的类型;同时,print_type::operator()<>
需要一个wrap
和wrap
——当然这是将拒绝编译。Some terminology, paraphrased from the Boost.MPL reference manual:
type
apply
Thus we know that
wrap<>
is a metafunction, and thatwrap<mpl::_>
is both a placeholder expression and a metafunction.When
mpl::for_each<>
is passed a metafunction or a metafunction class for theTransformOp
template argument, it evaluates that metafunction/metafunction class to obtain the result of the transformation. Consequently, if you want to pass a raw placeholder expression without further evaluation, your placeholder expression must not meet the criteria of a metafunction or metafunction class.In your scenario, because
wrap<>
is a metafunction,mpl::for_each<>
is evaluating it and producingA
andB
as the transformed types; meanwhile,print_type::operator()<>
is expecting awrap<A>
andwrap<B>
-- of course this will refuse to compile.