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
Post a Comment