This question is mostly to understand the logic and naming conventions in the design of the cast functions. Here, I simply pick the example of const_cast
and then I give the example of a custom cast function.
I could be wrong, but in my opinion cast functions are way to tell the compiler something that we know and the compiler doesn't know and to by pass certain rules process if necessary. At least this is the logic in all built in cast functions (
reinterpret_cast
,const_cast
,dynamic_cast
, and C-casts).
So the example is simple, if I have an object const A
. I can produce a non-const reference:
A const a;
A& a2 = const_cast<A&>(a); // I "know" from the logic of the code that 'a' can really be modified
I could write a function,
A& to_non_const(A const& a){return const_cast<A&>(a);}
and use it like this
A const a;
A& a2 = to_non_const(a);
The first question is, why is const_cast
redundant in the parametrized type?, why isn't there a function to_non_const
that automatically deduces the full target type?
I know how to use const_cast
, but I mostly want to know the logic about it as a guideline to write other custom "cast" function. This is example of a custom cast function,
template<class T>
struct positive{ // nothing private for simplicity
T val_;
positive(T const& t) : val_(t){if(t < 0) throw std::domain_error("number is negative");}
...
};
double cinco = 5;
positive<double> p(cinco); // ok, but checks
positive<double> p = positive_cast<positive<double>>(cinco); // I "know" it is positive
where
template<class Positive, class T>
Positive positive_cast(T const& t){
Positive ret;
ret.val_ = t; // assigns with no check
return ret;
}
The idea here is that I have a cast function that bypassed the check. (For example, imagine, because the check is expensive.) In other words, I am doing something locally unsafe (to the logic of the program), but a bit safer and controlled than positive<double> p = reinterpret_cast<positive<double> const&>(cinco);
.
Is this a good a design, I replicated the const_cast
logic, and I could it in a simpler way.
template<class T>
positive<T> to_positive(T const& t){
return positive_cast<positive<T>>(t);
}
Used as this:
double cinco = 5;
positive<double> p(cinco); // ok, but checks
positive<double> p = to_positive(cinco); // I "know" it is positive
Would this be a consistent correct "cast" function? Using the "cast" version from before I can make it clear that there is no check, but to_positive
can be understood as having a check.
There are no serious discussions around of how an unsafe cast function should be written and what conventions to follow. It looks like some people call "cast" to any conversion function regardless of the semantics.
I found some other examples around, but it is hard to find a common pattern.
- Boost.Quantity quantity_cast
- Boost.NumericConversion numeric_cast
- Boost.Conversion
- Boost.LexicalCast
- Standard hierarchy cast
In all the cases I could see the cast behave like functions and they are explicit in the target type, and in general there are no convenience functions that deduce parameters automatically.
Aucun commentaire:
Enregistrer un commentaire