Thank you for this detailed email, i will study it carefully. Romain
Le 8 févr. 2013 à 13:16, Yan Zhou <[email protected]> a écrit : > This morning I was frustrated by a compilation error, below is a scratch of > the problem > > // MyClass1.h > template <typename T> > class MyClass {/*...*/}; > > #include <RcppCommon.h> > namespace Rcpp { > template <typename T> inline SEXP wrap(const MyClass1<T> &object) {/* ... */} > } > #include <Rcpp.h> > //... > > // MyClass2.h Similar to MyClass1.h > > // some.cpp > #include "MyClass1.h" > #include "MyClass2.h" > > MyClass2<T> object; > Rcpp::List::create(Rcpp::Named("MyClass2") = object); > > I believe you already see the problem. An implicit conversion happens and it > implicitly call Rcpp::wrap. However because of MyClass1.h, the declaration of > wrap for MyClass2 was never seen before Rcpp.h. So the dispatch never reach > my wrap. This problem will always happen as long as implicit call to > Rcpp::wrap (qualified name) happens and there are more than a handful > headers. The reason to write libraries and use headers is that we don't need > to remember what is inside. In this case. I have to remember what's there. > And the requirement that the declaration happens before Rcpp.h, is sometimes > just impossible. > > An easy way to fix this is, at the call site of Rcpp::wrap (which I finally > tracked down), > instead of > > ::Rcpp::wrap(object); > > I changed it to, > > using Rcpp::wrap; > wrap(object); > > This is basically the same trick of using std::swap. Now because wrap is an > unqualified dependent name, it will have a second chance at POI (an ADL > lookup). In the original implementation, Rcpp::wrap is a qualified dependent > name, and at the second phase it will only look for template specialization > (see the PS at the end of the email). > > However a quick grep shows that there are over 200 ::Rcpp::wrap in Rcpp > headers. So such change is almost impossible. There will almost certainly be > some disaster introduced by such a big change. > > So I though of another workaround, which you may find interesting. > > Currently Rcpp::wrap looks like this, > > template <typename T> > inline SEXP wrap(const T& object){ > return internal::wrap_dispatch( object, typename > ::Rcpp::traits::wrap_type_traits<T>::wrap_category() ) ; > } > > Instead of having it call wrap_dispatch directly, I added another layer of > indirection, > > // in namespace internal > template <typename T> > inline SEXP wrap_implicit(const T& object){ > return wrap_dispatch( object, typename > ::Rcpp::traits::wrap_type_traits<T>::wrap_category() ) ; > } > > template <typename T> > inline SEXP wrap(const T& object){ > using ::Rcpp::internal::wrap_implicit; > return wrap_implicit(object); > } > > This is basically the same as before. Now, because both wrap is a template, > and thus wrap_implicit is a dependent name and according to the two phase > lookup rule, wrap_implicit(object) will be resolved at POI. All it matters > is wrap_implicit was seen before POI. A side effect (benefit) is that > wrap_implicit does not have to be defined in the namespace Rcpp. I can be in > global namespace of in the class namespace and still be found through ADL. > > Explicit call to wrap can already works this way, for example > > #include <Rcpp.h> > > namespace my_ns { > class MyType {..}; > SEXP wrap (const MyType &object) {...} > > } > > my_ns::MyType my_object; > using Rcpp::wrap; > wrap(my_object); // call my_ns::wrap > wrap(RcppTypeObject); // call Rcpp::wrap > wrap(SomeUnknownType); // call Rcpp:wrap, possible error after all > > The additional layer of wrap_implicit only affects explicit call to > Rcpp::wrap, such as > Rcpp::wrap(my_object); // Oops! no my_ns::wrap_implicit yet > In this case, since the user explicitly request Rcpp::wrap, then of course > he/she need to define it in Rcpp namespace (though still can be defined after > Rcpp.h, as long as it is before POI) > > In the user perspective it also affect some implicit conversion to SEXP. And > thus the name wrap_implicit. Since this is more or less behind the scene, I > think a little more obstructed name is better. > > The bottom line is that, with such change, specialized wrap does not have to > be declared before Rcpp.h > > However there may be some (important) corner cases that I haven't thought of > that may cause troubles. In addition, qualified name has its advantage over > the using idiom, and you known Rcpp far better than I to judge this problem. > > Best, > > Yan Zhou > > P.S. The document Rcpp-extending.pdf is not quite accurate. Section 2.3, it > is not partial specialization. It is actually function templates overloading. > There is no such thing as function partial specialization. A full > specialization (section 2.2) only need to be seen before POI, does not have > be before Rcpp.h. In Section 2.3, it is required to have the decleration > before wrap.h is that it is not a specialization at all but totally another > overloaded function. Without it, qualified name call ::Rcpp::wrap will always > resolve to the one in wrap.h. > _______________________________________________ > Rcpp-devel mailing list > [email protected] > https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel _______________________________________________ Rcpp-devel mailing list [email protected] https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel
