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

Reply via email to