type wrapper error with boost::mpl::for_each (section 9.1.1 from Abrahams & Gurtovoy book)
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()
);
/* Outp开发者_开发百科ut:
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 ==========
Some terminology, paraphrased from the Boost.MPL reference manual:
- A metafunction is a type with a nested type named
type
- A metafunction class is a type with a nested metafunction named
apply
- A placeholder expression is a type that is either an MPL placeholder or a class template specialization with at least one argument that itself is a placeholder expression
Thus we know that wrap<>
is a metafunction, and that wrap<mpl::_>
is both a placeholder expression and a metafunction.
When mpl::for_each<>
is passed a metafunction or a metafunction class for the TransformOp
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 producing A
and B
as the transformed types; meanwhile, print_type::operator()<>
is expecting a wrap<A>
and wrap<B>
-- of course this will refuse to compile.
精彩评论