2016-07-06 16 views
4

Ich versuche, den Sinn der Verwendung von Fusion-Transformation zu erhalten und bin mit diesem einfachen Beispiel stapfte:Erhöhung Fusion Art Manipulation und as_vector

#include <boost/fusion/include/is_sequence.hpp> 
#include <boost/fusion/include/as_vector.hpp> 
#include <boost/fusion/include/make_vector.hpp> 
#include <boost/fusion/include/transform.hpp> 

template< typename T > 
struct S { 
    typedef T type; 
}; 

struct S_f { 
    template< typename T > 
    struct result { 
     typedef typename T::type type; 
    }; 
}; 

int main() { 
    using namespace boost; 
    typedef fusion::vector<S<int>> from_type; 
    BOOST_MPL_ASSERT((fusion::traits::is_sequence< fusion::vector<int> >)); 

    typedef fusion::result_of::transform< from_type, S_f >::type to_type; 
    BOOST_MPL_ASSERT((fusion::traits::is_sequence<to_type>)); 

    typedef fusion::result_of::as_vector<to_type>::type value_type; // error 
} 

Das behauptet Pass aber die typedef für value_type mit dem Fehler fehlschlägt unten. Ich konnte keine Diskrepanz zwischen dem Code und den Dokumenten finanzieren und auch keine Abhilfe bei Stackoverflow- oder Boost-Mailinglisten.

AFAICT der Code ist korrekt: das Ergebnis der Anwendung der Transformationsmetafunktion ist eine transform_view und eine transform_view ist eine Sequenz, wie durch die bestandenen Behauptungen gezeigt. Die Anwendung der metafunktion as_vector auf der transform_view schlägt jedoch fehl. Was gibt?!

Jede Hilfe wird geschätzt. Ich bin NICHT daran interessiert, MPL zu mischen. Ich weiß, dass ich einen Umweg über MPL machen kann und ein paar Fragen zu SO Fragen, die nach Typmanipulation fragen, haben Antworten, die MPL befürworten. Laut den Unterlagen würde ich MPL nicht brauchen.

clang++ -std=c++1z -c t.cpp 
In file included from main.cpp:4: 
In file included from /usr/local/include/boost/fusion/include/transform.hpp:11: 
In file included from /usr/local/include/boost/fusion/algorithm/transformation/transform.hpp:11: 
In file included from /usr/local/include/boost/fusion/view/transform_view/transform_view.hpp:15: 
In file included from /usr/local/include/boost/fusion/view/transform_view/transform_view_iterator.hpp:18: 
/usr/local/include/boost/fusion/view/transform_view/detail/value_of_impl.hpp:37:74: error: no type named 'type' in 'boost::mpl::apply<boost::fusion::detail::apply_transform_result<S_f>, S<int>, mpl_::na, mpl_::na, mpl_::na, mpl_::na>' 
       typedef typename mpl::apply<transform_type, value_type>::type type; 
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~ 
/usr/local/include/boost/fusion/iterator/value_of.hpp:52:15: note: in instantiation of template class 'boost::fusion::extension::value_of_impl<boost::fusion::transform_view_iterator_tag>::apply<boost::fusion::transform_view_iterator<boost::fusion::vector_iterator<boost::fusion::vector<S<int>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_>, 0>, S_f> >' requested here 
      : extension::value_of_impl<typename detail::tag_of<Iterator>::type>:: 
      ^
/usr/local/include/boost/fusion/container/vector/detail/cpp03/preprocessed/as_vector10.hpp:19:49: note: in instantiation of template class 'boost::fusion::result_of::value_of<boost::fusion::transform_view_iterator<boost::fusion::vector_iterator<boost::fusion::vector<S<int>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_>, 0>, S_f> >' requested here 
      typedef typename fusion::result_of::value_of<I0>::type T0; 
               ^
/usr/local/include/boost/fusion/container/vector/convert.hpp:26:17: note: in instantiation of template class 'boost::fusion::detail::barrier::as_vector<1>::apply<boost::fusion::transform_view_iterator<boost::fusion::vector_iterator<boost::fusion::vector<S<int>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_>, 0>, S_f> >' requested here 
       template apply<typename result_of::begin<Sequence>::type>::type 
       ^
main.cpp:26:32: note: in instantiation of template class 'boost::fusion::result_of::as_vector<boost::fusion::transform_view<boost::fusion::vector<S<int>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_>, S_f, boost::fusion::void_> >' requested here 
    typedef fusion::result_of::as_vector<to_type>::type value_type; // error 
          ^
1 error generated. 

Antwort

5

Das Problem mit Metaprogrammierung ist, dass, wenn Sie die Voraussetzungen eines metafunction nicht entsprechen, können Sie eine Menge sinnlose Fehler bekommen. Die Anforderung an transform ist, dass F eine unäre Polymorphic Function Object ist. Die Erklärung dessen, was das in der Dokumentation ist, ist ein wenig schwach, aber Sie können aus den Beispielen erkennen: Dies ist ein Objekt, das Sie mit Argumenten aufrufen können. Das heißt, result_of<F(T)>::type muss wohlgeformt sein.

Was sind Sie auf transform vorbei ist:

struct S_f { 
    template< typename T > 
    struct result { 
     typedef typename T::type type; 
    }; 
}; 

Das ist nicht eine polymorphe Funktion Objekt ist. Es ist auch keine Metafunktionsklasse. Boost.Fusion oder Boost.MPL könnten dies nicht verstehen. Wo dies besonders verwirrend ist ist, dass die transform<> Metafunktion ist faul - so sieht es aus, als ob Sie diesen Teil richtig gemacht haben. Es ist nur in as_vector<>, dass die Transformation tatsächlich angewendet wird, also sieht es so aus, dass dort der Punkt des Scheiterns ist.

Um es auf eine polymorphe Funktion Objekt zu konvertieren, ändern Sie einfach die verschachtelte result Klassenvorlage in einem Call-Betreiber:

struct S_f { 
    template< typename T > 
    typename T::type operator()(T); 
}; 

Keine Definition erforderlich, da Sie eigentlich nicht nennen. Mit diesem Fix wird Ihr Code kompiliert.