使用 boost::mpl::for_each 类型包装器错误(Abrahams & Gurtovoy 书中的第 9.1.1 节)

发布于 2024-12-06 16:39:19 字数 3132 浏览 6 评论 0原文

以下代码几乎是从 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情定在深秋 2024-12-13 16:39:19

一些术语,摘自 Boost.MPL 参考手册

  • 元函数是具有名为type的嵌套类型的类型
  • 元函数类是具有名为apply的嵌套元函数的类型
  • 占位符表达式是一种类型,它可以是 MPL 占位符,也可以是类模板特化,并且至少有一个参数本身就是占位符表达式。

因此我们知道 wrap<>是一个元函数,并且 wrap 既是占位符表达式又是元函数。

当为 TransformOp 模板参数传递 mpl::for_each<> 元函数或元函数类时,它会评估该元函数/元函数类以获得转换结果。因此,如果您想要传递原始占位符表达式而不进行进一步计算,则您的占位符表达式不得满足元函数或元函数类的条件。

在您的场景中,因为 wrap<> 一个元函数,mpl::for_each<> 正在评估它并生成 AB 作为转换后的类型;同时,print_type::operator()<>需要一个wrapwrap——当然这是将拒绝编译。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文