おっしゃる通り。だけど、そもそも、誰がなにをインスタンス化しようとしてエラーが出ているんだろう。今までboost::recursive_variant_を完全型にしてしのいできたけど、どうして完全型でなければならないのか整理してみようと思う。

さて、GCC 4.6.0 20110212において、下記のコードがコンパイルできない。

#include <map>
#include <boost/variant.hpp>

int main(int argc, char* argv[]) {
  typedef boost::make_recursive_variant<
    boost::blank,
    std::map<int, boost::recursive_variant_>
  >::type variant_type;
  variant_type v;
  return 0;
}

コンパイルエラーから原因を読み解こうと思ったんだけど、どうしても判らなかったので断念。判りやすい例題として、次のようなものを用意した。これもコンパイルできない。

#include <boost/variant.hpp>

template <typename T>
struct holder {
  T value;
};

int main(int argc, char* argv[]) {
  typedef boost::make_recursive_variant<
    boost::blank,
    holder<boost::recursive_variant_>
  >::type variant_type;
  variant_type v;
  return 0;
}

コンパイルエラーが意味不明だ。もうすこし判りやすいコンパイルエラーを出してみよう。

#include <boost/variant.hpp>

template <typename T>
struct holder {
  T value;
};

template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
inline void f(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const*) {}

int main(int argc, char* argv[]) {
  typedef boost::make_recursive_variant<
    boost::blank,
    holder<boost::recursive_variant_>
  >::type variant_type;
  variant_type* x = 0;
  f(x);
  return 0;
}

マクロが判りにくいので、展開する。

#include <boost/variant.hpp>

template <typename T>
struct holder {
  T value;
};

template <typename T0, typename T1>
inline void f(boost::variant<T0, T1> const*) {}

int main(int argc, char* argv[]) {
  typedef boost::make_recursive_variant<
    boost::blank,
    holder<boost::recursive_variant_>
  >::type variant_type;
  variant_type* x = 0;
  f(x);
  return 0;
}

ようやく、判りやすくなった。関数fを書き換えてみよう(まだコンパイルは通らない)。

#include <boost/variant.hpp>

template <typename T>
struct holder {
  T value;
};

template <typename T0>
inline void f(boost::variant<T0, holder<boost::recursive_variant_> > const*) {}

int main(int argc, char* argv[]) {
  typedef boost::make_recursive_variant<
    boost::blank,
    holder<boost::recursive_variant_>
  >::type variant_type;
  variant_type* x = 0;
  f(x);
  return 0;
}

ここまで来れば、問題は明白だ。boost::recursive_variant_を完全型にするか、holder<boost::recursive_variant_>を特殊化するしかない。ちなみに、規格のどの項目によって、この問題が規定されているのか、いまだに判らない。なぜなんだろう。



ここからは、最初のコードのコンパイルエラーから原因を読み解こうと思ったときの悪戦苦闘メモ。

In file included from /opt/morla_exp/gcc_exp/lib/gcc/x86_64-apple-darwin10.6.0/4.6.0/../../../../include/c++/4.6.0/bits/stl_algobase.h:65:0,
                 from /opt/morla_exp/gcc_exp/lib/gcc/x86_64-apple-darwin10.6.0/4.6.0/../../../../include/c++/4.6.0/bits/stl_tree.h:63,
                 from /opt/morla_exp/gcc_exp/lib/gcc/x86_64-apple-darwin10.6.0/4.6.0/../../../../include/c++/4.6.0/map:60,
                 from /Users/moyu/Workspace/morla/src/recipe/recipe_recursive_variant4.cpp:1:
/opt/morla_exp/gcc_exp/lib/gcc/x86_64-apple-darwin10.6.0/4.6.0/../../../../include/c++/4.6.0/bits/stl_pair.h: In instantiation of ‘std::pair<const int, boost::recursive_variant_>’:
/opt/morla_exp/boost/include/boost/variant/detail/visitation_impl.hpp:260:1:   instantiated from ‘typename Visitor::result_type boost::detail::variant::visitation_impl(int, int, Visitor&, VoidPtrCV, mpl_::false_, NoBackupFlag, Which*, step0*) [with Which = mpl_::int_<0>, step0 = boost::detail::variant::visitation_impl_step<boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<2l>, boost::blank, boost::mpl::l_item<mpl_::long_<1l>, boost::recursive_wrapper<std::map<int, boost::variant<boost::detail::variant::recursive_flag<boost::blank>, std::map<int, boost::recursive_variant_>, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_>, std::less<int>, std::allocator<std::pair<const int, boost::variant<boost::detail::variant::recursive_flag<boost::blank>, std::map<int, boost::recursive_variant_>, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> > > > >, boost::mpl::l_end> > >, boost::mpl::l_iter<boost::mpl::l_end> >, Visitor = boost::detail::variant::destroyer, VoidPtrCV = void*, NoBackupFlag = boost::variant<boost::detail::variant::recursive_flag<boost::blank>, std::map<int, boost::recursive_variant_>, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_>::has_fallback_type_, typename Visitor::result_type = void, mpl_::false_ = mpl_::bool_<false>]’
/opt/morla_exp/boost/include/boost/variant/variant.hpp:1776:13:   instantiated from ‘static typename Visitor::result_type boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::internal_apply_visitor_impl(int, int, Visitor&, VoidPtrCV) [with Visitor = boost::detail::variant::destroyer, VoidPtrCV = void*, T0_ = boost::detail::variant::recursive_flag<boost::blank>, T1 = std::map<int, boost::recursive_variant_>, T2 = boost::detail::variant::void_, T3 = boost::detail::variant::void_, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_, typename Visitor::result_type = void]’
/opt/morla_exp/boost/include/boost/variant/variant.hpp:1787:13:   instantiated from ‘typename Visitor::result_type boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::internal_apply_visitor(Visitor&) [with Visitor = boost::detail::variant::destroyer, T0_ = boost::detail::variant::recursive_flag<boost::blank>, T1 = std::map<int, boost::recursive_variant_>, T2 = boost::detail::variant::void_, T3 = boost::detail::variant::void_, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_, typename Visitor::result_type = void]’
/opt/morla_exp/boost/include/boost/variant/variant.hpp:1188:9:   instantiated from ‘void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::destroy_content() [with T0_ = boost::detail::variant::recursive_flag<boost::blank>, T1 = std::map<int, boost::recursive_variant_>, T2 = boost::detail::variant::void_, T3 = boost::detail::variant::void_, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_]’
/opt/morla_exp/boost/include/boost/variant/variant.hpp:1195:9:   instantiated from ‘boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::~variant() [with T0_ = boost::detail::variant::recursive_flag<boost::blank>, T1 = std::map<int, boost::recursive_variant_>, T2 = boost::detail::variant::void_, T3 = boost::detail::variant::void_, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_]’
/Users/moyu/Workspace/morla/src/recipe/recipe_recursive_variant4.cpp:10:16:   instantiated from here
/opt/morla_exp/gcc_exp/lib/gcc/x86_64-apple-darwin10.6.0/4.6.0/../../../../include/c++/4.6.0/bits/stl_pair.h:93:11: error: ‘std::pair<_T1, _T2>::second’ has incomplete type
/opt/morla_exp/boost/include/boost/variant/variant_fwd.hpp:232:12: error: forward declaration of ‘struct boost::recursive_variant_’

流し読みすると、boost/variant/detail/visitation_impl.hppの260行めが怪しい。

    BOOST_PP_REPEAT(
          BOOST_VARIANT_VISITATION_UNROLLING_LIMIT
        , BOOST_VARIANT_AUX_APPLY_VISITOR_STEP_CASE
        , _ 
        )   

Boost.Preprocessor出現。これだとどこでコンパイルエラーが出ているのか判らないので、手でリピートしてみる。ちなみに、デフォルトではBOOST_VARIANT_VISITATION_UNROLLING_LIMIT = BOOST_VARIANT_LIMIT_TYPES = BOOST_MPL_LIMIT_LIST_SIZEなので20。

    case (Which::value + 0):
      return visitation_impl_invoke(
          internal_which, visitor, storage, static_cast<T0*>(0), no_backup_flag, 1L);
    case (Which::value + 1):
      return visitation_impl_invoke(
          internal_which, visitor, storage, static_cast<T1*>(0), no_backup_flag, 1L);
    // 中略
    case (Which::value + 19):
      return visitation_impl_invoke(
          internal_which, visitor, storage, static_cast<T19*>(0), no_backup_flag, 1L);

コンパイルエラーによると、case (Which::value + 1)のvisitation_impl_invokeのあたりで具現化されているらしい。とすると、static_cast<T1*>(0)のあたりが怪しいんだろう。T1はstep0::next::typeだ。step0がどんな型なのかはエラーメッセージに書いてある。整形して読みやすくしたT1。

T1 = boost::recursive_wrapper<
  std::map<
    int,
    boost::variant<
      boost::detail::variant::recursive_flag<boost::blank>,
      std::map<int, boost::recursive_variant_>,
      boost::detail::variant::void_, ...
    >,
    std::less<int>,
    std::allocator<
      std::pair<
        const int,
        boost::variant<
          boost::detail::variant::recursive_flag<boost::blank>,
          std::map<int, boost::recursive_variant_>,
          boost::detail::variant::void_, ...
        >
      >
    >
  > 
>

でも、なんでエラーが出るのか判らない。static_cast<T1*>(0)自体は、たとえT1がどんな型であれ、動くと思うし……。

というわけで断念。

このページへのコメント

zy6Ab8 <a href="http://lnmjrjbmkguc.com/">lnmjrjbmkguc</a>, [url=http://eknmhhwmnpaf.com/]eknmhhwmnpaf[/url], [link=http://pqjywvdctokd.com/]pqjywvdctokd[/link], http://rwnmuhgrjzky.com/

0
Posted by vcvzrxh 2013年11月14日(木) 13:48:49 返信

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

メンバーのみ編集できます