c++ - Implicit conversion not happening -
the last question asked stumbled upon when trying understanding thing... can't understand (not day).
this quite long question statement, @ least hope question might prove useful many people , not me.
the code have following:
template <typename t> class v; template <typename t> class s; template <typename t> class v { public: t x; explicit v(const t & _x) :x(_x){} v(const s<t> & s) :x(s.x){} }; template <typename t> class s { public: t &x; explicit s(v<t> & v) :x(v.x) {} }; template <typename t> v<t> operator+(const v<t> & a, const v<t> & b) { return v<t>(a.x + b.x); } int main() { v<float> a(1); v<float> b(2); s<float> c( b ); b = + v<float>(c); // 1 -- compiles b = + c; // 2 -- fails b = c; // 3 -- compiles return 0; }
expressions 1 , 3 work perfectly, while expression 2 not compile.
if have understood properly, happens is:
expression 1
- c is implicitly converted
const
using standard conversion sequence (consisting on 1 qualification conversion). v<float>(const s<t> & s)
called , temporalconst v<float>
object generated (let's call t). const-qualified because temporal value.- a converted const c.
operator+(const v<float> & a, const v<float> & b)
called, resulting in temporal of typeconst v<float>
can call q.- the default
v<float>::operator=(const & v<float>)
called.
am ok here? if made subtle mistake please, let me know, trying gain understanding implicit casting deep possible...
expression 3
- c converted
v<float>
. that, have user-defined conversion sequence:
1.1. first standard conversion:s<float>
const s<float>
via qualification conversion.
1.2. user-defined conversion:const s<float>
v<float>
viav<float>(const s<t> & s)
constructor.
1.3 second standard conversion:v<float>
const v<float>
via qualification conversion. - the default
v<float>::operator=(const & v<float>)
called.
expression 2?
what not understand why there problem second expression. why following sequence not possible?
- c converted
v<float>
. that, have user-defined conversion sequence:
1.1. initial standard conversion:s<float>
const s<float>
via qualification conversion.
1.2. user-defined conversion:const s<float>
v<float>
viav<float>(const s<t> & s)
constructor.
1.3. final standard conversion:v<float>
const v<float>
via qualification conversion. - steps 2 6 same in case of expression 1.
after reading c++ standard though: 'hey! maybe problem has to 13.3.3.1.2.3!' states:
if user-defined conversion specified template conversion function, second standard conversion sequence must have exact match rank.
but cannot case since qualification conversion has exact match rank...
i have no clue...
well, whether have answer or not, reading here :)
as edric pointed out, conversions not considered during template argument deduction. here, have 2 contexts template parameter t can deduced type of arguments:
template<class t> v<t> operator+(v<t> const&, v<t> const&); ~~~~~~~~~~~ ~~~~~~~~~~~~
but try invoke function template v<float>
on left-hand side , s on right hand side. template argument deduction results in t=float left hand side , you'll error right hand side because there no t v<t>
equals s<t>
. qualifies template argument deduction failure , template ignored.
if want allow conversions operator+ shouldn't template. there following trick: can define inline friend inside of class template v:
template<class t> class v { public: v(); v(s<t> const&); // <-- note: no explicit keyword here friend v<t> operator+(v<t> const& lhs, v<t> const& rhs) { ... } };
this way, operator not template anymore. so, there no need template argument deduction , invocation should work. operator found through adl (argument dependent lookup) because left-hand side v<float>
. right-hand side converted v<float>
well.
it possible disable template argument deduction specific argument. example:
template<class t> struct id {typedef t type;}; template<class t> t clip( typename id<t>::type min, t value, typename id<t>::type max ) { if (value<min) value=min; if (value>max) value=max; return value; } int main() { double x = 3.14; double y = clip(1,x,3); // works, t=double }
even though type of first , last argument int, not considered during template argument deduction because id<t>::type
not so-called *deducible context`. so, t deduced according second argument, results in t=double no contradictions.
Comments
Post a Comment