3

MPL プレースホルダーを理解するのに苦労しています。
このコードがコンパイルに失敗する理由を誰か説明してもらえますか?

数値 0、1、2 が出力されることを期待しますが、コンパイラが Wrapper のデフォルト テンプレート パラメーターの型を決定しようとするときに、プレースホルダーが実際の型に置き換えられないようです。

#include <iostream>
#include <boost/mpl/inherit.hpp>
#include <boost/mpl/inherit_linearly.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/vector.hpp>

template <typename T> struct Traits;

template<> struct Traits<int>  { typedef boost::mpl::int_<0> type; };
template<> struct Traits<char> { typedef boost::mpl::int_<1> type; };
template<> struct Traits<bool> { typedef boost::mpl::int_<2> type; };

template <typename T, typename Type=typename Traits<T>::type > struct Wrapper
{
    Wrapper() { std::cout << "Value: " << Type::value << std::endl; }

    T value;
};

int main()
{
    typedef boost::mpl::inherit_linearly<
                boost::mpl::vector<int, char, bool>,
                boost::mpl::inherit<boost::mpl::_1, Wrapper<boost::mpl::_2> > >::type Object;

    Object obj;

    return 0;
}

これは gcc-4.1.2 からのエラーです (私は知っています... 古いコンパイラが動作しています)

# g++4 -I ../boost test.cpp -o test
test.cpp: In function 'int main()':
test.cpp:24: error: invalid use of undefined type 'struct Traits<mpl_::arg<2> >'
test.cpp:7: error: declaration of 'struct Traits<mpl_::arg<2> >'
test.cpp:24: error: template argument 2 is invalid
test.cpp:24: error: template argument 2 is invalid
test.cpp:24: error: template argument 2 is invalid
test.cpp:24: error: expected initializer before 'Object'
test.cpp:26: error: 'Object' was not declared in this scope
test.cpp:26: error: expected `;' before 'obj'

編集:以下 の Acorbe の回答の後、彼が提案したソリューションが私のニーズに合わない理由を示すために、サンプル プログラムの変形を作成しました。これは私が求めているものを明確にします。この場合、テキスト TYPE_A、TYPE_B、TYPE_A が出力されることを期待します。g++ エラーは同じです。

#include <iostream>
#include <boost/mpl/inherit.hpp>
#include <boost/mpl/inherit_linearly.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/vector.hpp>

enum WrapperType { TYPE_A, TYPE_B };

template <typename T> struct Traits;

template<> struct Traits<int>  { typedef boost::mpl::int_<TYPE_A> type; };
template<> struct Traits<char> { typedef boost::mpl::int_<TYPE_B> type; };
template<> struct Traits<bool> { typedef boost::mpl::int_<TYPE_A> type; };

template <typename T, typename Type=typename Traits<T>::type > struct Wrapper;

template <typename T>
struct Wrapper<T, boost::mpl::int_<TYPE_A> >
{
    Wrapper() : value (0) { std::cout << "TYPE_A" << std::endl; }

    T value;
};

template <typename T>
struct Wrapper<T, boost::mpl::int_<TYPE_B> >
{
    Wrapper() { std::cout << "TYPE_B" << std::endl; }

    T value;
};

int main()
{
    typedef boost::mpl::inherit_linearly<
                boost::mpl::vector<int, char, bool>,
                boost::mpl::inherit<boost::mpl::_1, Wrapper<boost::mpl::_2> > >::type Object;

    Object obj;

    return 0;
}

これは gcc-4.5.4 のエラーです

# g++ -I ../boost test.cpp -o test
test.cpp: In functie ‘int main()’:
test.cpp:37:79: fout: invalid use of incomplete type ‘struct Traits<mpl_::arg<2> >’
test.cpp:9:34: fout: declaration of ‘struct Traits<mpl_::arg<2> >’
test.cpp:37:79: fout: template argument 2 is invalid
test.cpp:37:81: fout: template argument 2 is invalid
test.cpp:37:83: fout: template argument 2 is invalid
test.cpp:37:91: fout: expected initializer before ‘Object’
test.cpp:39:9: fout: ‘Object’ was not declared in this scope
test.cpp:39:16: fout: expected ‘;’ before ‘obj’

これは (部分的に) clang++-3.1 からのエラーです:

test.cpp:15:50: error: implicit instantiation of undefined template 'Traits<mpl_::arg<2> >'
    template <typename T, typename Type=typename Traits<T>::type > struct Wrapper;
                                                 ^
test.cpp:37:57: note: in instantiation of default argument for 'Wrapper<mpl_::arg<2> >' required here
                    boost::mpl::inherit<boost::mpl::_1, Wrapper<boost::mpl::_2> > >::type Object;
                                                        ^~~~~~~~~~~~~~~~~~~~~~~
test.cpp:9:34: note: template is declared here
    template <typename T> struct Traits;
4

2 に答える 2

1

コードに少し変更を加えてtypedef、デフォルトのテンプレートパラメータによって引き起こされたものを2つtypedefの単純なものに分割しました。

このことを考慮:

template < typename T , typename Super_Type = Traits<T> > struct Wrapper
{ 
     typedef typename Super_Type::type Type;
     Wrapper() { std::cout << "Value: " << Type::value << std::endl; }

     T value;
};

このようにコンパイルします。私の疑わしいのは、元の式(正しいものの)が複雑すぎてコンパイラーで正しく拡張できないことです。

于 2012-10-24T18:48:25.233 に答える
1

わかりました...私はそれをクラックしたようです...
多くの場合、余分なレベルの抽象化がうまくいきました。

プレースホルダーと共に mpl::apply1 に渡されるメタ関数クラス (genWrapper) を作成しました。そこにあるメタ関数は、期待されるラッパー タイプを返します。

これが結果のプログラムです (第 2 バージョン)。
ヘルプとポインタをありがとう。

#include <iostream>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/inherit.hpp>
#include <boost/mpl/inherit_linearly.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/vector.hpp>

enum WrapperType { TYPE_A, TYPE_B };

template <typename T> struct Traits;

template<> struct Traits<int>  { typedef boost::mpl::int_<TYPE_A> type; };
template<> struct Traits<char> { typedef boost::mpl::int_<TYPE_B> type; };
template<> struct Traits<bool> { typedef boost::mpl::int_<TYPE_A> type; };

template <typename T, typename Type = typename Traits<T>::type> struct Wrapper;

template <typename T>
struct Wrapper<T, boost::mpl::int_<TYPE_A> >
{
    Wrapper() : value (0) { std::cout << "TYPE_A" << std::endl; }

    T value;
};

template <typename T>
struct Wrapper<T, boost::mpl::int_<TYPE_B> >
{
    Wrapper() { std::cout << "TYPE_B" << std::endl; }

    T value;
};

struct genWrapper
{
    template <typename T>
    struct apply
    {
        typedef Wrapper<T> type;
    };
};

int main()
{
    typedef boost::mpl::inherit_linearly<
                boost::mpl::vector<int, char, bool>,
                boost::mpl::inherit<boost::mpl::_1, boost::mpl::apply1<genWrapper, boost::mpl::_2> > >::type Object;

    Object obj;

    return 0;
}

結果の出力は次のとおりです。

# g++4 -I ../boost test.cpp -o test
# ./test
TYPE_A
TYPE_B
TYPE_A
于 2012-10-25T11:54:57.267 に答える