I want to define a generic function whose arguments and the return type are identical instantiations of a template. This leads to an overly verbose definition. Is there a way to use a shorthand without polluting the enclosing namespace?
Example,
template<class CoordinateType, class ValueType>
struct PointWithValue {
CoordinateType x, y;
ValueType value;
}
template<class CoordinateType, class ValueType>
PointWithValue<CoordinateType, ValueType> interpolate(
PointWithValue<CoordinateType, ValueType> point1,
PointWithValue<CoordinateType, ValueType> point2)
{
...
}
One solution I can come up with is
template<class PointWithValueType>
PointWithValueType interpolate(
PointWithValueType point1, PointWithValueType point2)
But I am not really happy with this as it obfuscates what I expect as PointWithValueType
; it is only implicitly shown inside the body function. And if the caller passes a wrong argument, the error is unlikely to be clear and concise.
I would like something that looks like this
template<class CoordinateType, class ValueType>
using PointWithValueType = PointWithValue<CoordinateType, ValueType>;
PointWithValueType interpolate(
PointWithValueType point1, PointWithValueType point2)
As far as I can tell the above only works if I wrap it in a class and define the method as static
. It kind of works but it also changes the interface (puts the function inside a deeper named scope) and it relies on a class without members and with only a single static function which feels awkward and might confuse the user.
This is a general question, workarounds for this particular problem that do not apply to this class of problem are not suitable answers. Is there something similar to my using
example without drawbacks?
With traits and SFINAE, you might do
template <typename T>
struct IsPointWithValue : std::false_type {};
template <class CoordinateType, class ValueType>
struct IsPointWithValue<PointWithValue<CoordinateType, ValueType>> : std::true_type
{
// Possibly aliases to retrieve template parameters.
};
template<class T, std::enable_if_t<IsPointWithValue<T>::value, int> = 0>
T interpolate(T point1, T point2);
It can be a good idea to switch to using static assert with dedicated type trait (and probably to a concept with C++20) to check that template parameter is of required kind:
template
<
typename x_MaybePointWithValue
> class
is_point_with_value: public ::std::false_type {};
template
<
typename CoordinateType
, typename ValueType
> class
is_point_with_value<PointWithValue<CoordinateType, ValueType>>: public ::std::true_type {};
template
<
typename x_PointWithValue
> x_PointWithValue
interpolate(x_PointWithValue point1, x_PointWithValue point2)
{
static_assert
(
is_point_with_value<x_PointWithValue>::value
, "template parameter must be an instance of PointWithValue template"
);
}
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