c++ - SFINAE to enable cast operator only from derived to base class -


i have class template cfoo<t>. want allow implicit casts other instantiations of cfoo, template argument base class of t.

i tried use sfinae, neither of attempts worked on compiler tried (vc 2012 or gcc):

#include <type_traits>  template <class t> class cfoo { public:     template <class q>  operator      // typename std::enable_if<std::is_base_of<q, t>::value, cfoo<q>&>::type   // should work?      // typename std::enable_if<1, cfoo<q>&>::type                              // should work?      cfoo<q>&  // compiles, doesn't restrict on q want      () const {         return *(cfoo<q>*)this;     } };  class {}; class b : public {};  int main(int argc, char* argv[]) {     cfoo<b> b;     cfoo<a>& = b;     return 0; } 

why don't either of commented out attempts @ sfinae work here? in both cases error invalid initialization of a, if operator didn't called.

according [temp.deduct.conv]:

template argument deduction done comparing return type of conversion function template (call p) type required result of conversion (call a; see 8.5, 13.3.1.5, , 13.3.1.6 determination of type) described in 14.8.2.5.

in simple case:

template <class q> operator cfoo<q>& const; 

that's straightforward, try deduce cfoo<q>& against cfoo<a>&. there's other rules in section, deduction succeeds q == a.

both of other attempts fail same reason. i'll pick simpler one:

template <class q> operator typename std::enable_if<1, cfoo<q>&>::type const; 

here, we're trying deduce typename std::enable_if<1, cfoo<q>&>::type. non-deduced context (it's nested-name-specifier of type specified using qualified-id), deduction fails. conversion function won't considered, assignment fails no conversion found.

you need return type deduced context, sfinae has go here:

template <class q,           typename = std::enable_if_t<std::is_base_of<q, t>::value>> operator cfoo<q>& const; 

that way, have deduce (cfoo<q>&) - , deduction can succeed (if q base of t):

cfoo<a>& = b; // ok cfoo<int>& = b; // deduction failure on q, there's no viable conversion function                   // error 

that said, while got carried away solving template puzzles, t.c. points out, isn't solution because:

return *(cfoo<q>*)this; 

just reinterpret_cast (and const_cast) cannot possibly doing reasonable , (unless cfoo trivial) end undefined behavior trying access members wrong type.

you instead want add conversion constructor rather conversion function:

template <typename q,           typename = std::enable_if_t<std::is_base_of<t, q>::value>> cfoo(cfoo<q> const& ) { } 

that way, when do:

cfoo<a> = b; // not reference anymore 

you constructing new object valid.


Comments

Popular posts from this blog

Fail to load namespace Spring Security http://www.springframework.org/security/tags -

sql - MySQL query optimization using coalesce -

unity3d - Unity local avoidance in user created world -