Let's say I have a template function:
template <typename A, typename B>
A fancy_cast(B)
{
return {};
}
The intended usage is something like fancy_cast<int>(1.f)
.
But nothing stops the user from specifying the second template parameter manually: fancy_cast<int, int>(1.f)
, which would cause problems.
How can I prevent typename B
from being specified and force it to be deduced?
I've come up with this:
// Using this wrapper prevents the code from being
// ill-formed NDR due to [temp.res]/8.3
template <auto V> inline constexpr auto constant_value = V;
template <
typename A,
typename ...Dummy,
typename B,
typename = std::enable_if_t<constant_value<sizeof...(Dummy)> == 0>
>
A fancy_cast(B)
{
return {};
}
It appears to work, but it's extremely cumbersome. Is there a better way?
What about making fancy_cast
a variable template?
template <typename A>
struct fancy_cast_t {
template <typename B>
A operator()(B x) const { return x; }
};
template <typename A>
constexpr fancy_cast_t<A> fancy_cast {};
fancy_cast<int>(1.5); // works
fancy_cast<int, int>(1.5); // doesn't work
fancy_cast<int>.operator()<int>(1.5); // works, but no one would do this
This is not the most efficient solution, but you can create a class that has a template parameter for the type to convert to, and then have a constructor template that takes any type. Then if you add an operator T
for the type you instantiate the class with you can have that return correct value. That would look like
template<typename T>
struct fancy_cast
{
T ret;
template<typename U>
fancy_cast(U u) : ret(u) {} // or whatever you want to do to convert U to T
operator T() && { return std::move(ret); }
};
int main()
{
double a = 0;
int b = fancy_cast<int>(a);
}
This works because there is no way to specify the template parameter for the constructor since you can't actually call it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With