2

次のコードは、David Abrahams と Aleksey Gurtovoy による著書 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: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 ==========
4

1 に答える 1

2

Boost.MPLリファレンスマニュアルから言い換えたいくつかの用語:

  • メタ関数は、名前が付けられたネストされた型を持つ型ですtype
  • メタ関数クラスは、名前が付けられたネストされたメタ関数を持つ型です。apply
  • プレースホルダー式は、それ自体がプレースホルダー式である少なくとも 1 つの引数を持つ MPL プレースホルダーまたはクラス テンプレートの特殊化のいずれかである型です。

wrap<>したがって、これはメタ関数でありwrap<mpl::_>、プレースホルダー式メタ関数の両方であることがわかります。

mpl::for_each<>テンプレート引数のメタ関数またはメタ関数クラスが渡されると、そのTransformOpメタ関数/メタ関数クラスを評価して変換の結果を取得します。したがって、それ以上評価せずに生のプレースホルダー式を渡したい場合は、プレースホルダー式がメタ関数またはメタ関数クラスの基準を満たしていてはなりません。

あなたのシナリオでwrap<> 、メタ関数であるため、mpl::for_each<>それを評価し、変換された型として生成Aします。B一方、print_type::operator()<>andwrap<A>wrap<B>必要です -- もちろん、これはコンパイルを拒否します。

于 2011-09-27T19:58:06.880 に答える