Reputation: 1745
Considering the following function template func
declared within MyClass
class template:
template < T >
class MyClass {
public:
MyClass() = default;
// ...
template < typename oT >
oT func() {
return static_cast< oT >(_m); // alternative, return oT(_m);
}
// ...
protected:
T _m;
};
Is there any advantage in calling static_cast< oT >(_m)
over explicit instantiation i.e. oT(_m)
?
Upvotes: 0
Views: 305
Reputation: 76658
oT(_m)
will allow many more conversions than is probably intended. If static_cast<oT>(_m)
wouldn't be possible, then oT(_m)
will also try a const_cast
, static_cast
followed by const_cast
, reinterpret_cast
and reinterpret_cast
followed by const_cast
.
For example if T
is const int*
and oT
is double*
, then oT(_m)
will succeed, while static_cast<oT>(_m)
will fail. But using the result from oT(_m)
as if it was a pointer to a double
will result in undefined behavior.
If T
and oT
are pointers to classes that is maybe even more dangerous, since oT(_m)
will always compile, whether or not there is an inheritance relation between the two classes.
Even static_cast
allows for some conversions that may not be intended. For example it can downcast pointers to classes.
Another alternative is simply return _m;
. This is weaker than both variants above. It will only allow for copy-initialization. However that might be too weak depending on your use case. For example it will not use explicit constructors and conversion functions. On the other hand before C++17 it doesn't require oT
to be move-constructible, which the first two variants do require before C++17.
So you will need to decide what casts are supposed to be allowed and which ones are supposed to fail.
However, nothing prevents a user from calling func<T>()
to obtain the original type anyway and the user can then simply cast it however they like, so I am not sure what is gained here over a simple getter.
Even more so, the user can in either case call func<T&>()
and will get a reference to the member, thereby making the protected
somewhat pointless. Maybe the allowed types T
need to be constrained via SFINAE/requires-clause.
Upvotes: 5