Reputation: 929
I want to create a functor like std::plus<>()
but also add std::clamp
functionality to it.
Let's say it is a function plus_clamp<>(T MIN = numeric_limits<T>::min(), T MAX = ...max())
I started to look what implementation does std::plus<>()
have, and tried to repeat it.
So I wrote something like this.
struct plus_clamp {
template<typename T = void>
constexpr T operator()(const T& lhs, const T& rhs, T MIN = nl::min(),T MAX = nl::max()) {
T result = std::plus<>();
result = std::clamp(result, MIN,MAX);
return result;
}
};
But when I try to use that function with std::transform(a.begin(),a.end(),b.begin(),result.begin(), plus_clamp<>())
I get compiler error
error: expected '(' for function-style cast or type construction
error: expected expression(at template parameter arg)
error: expected expression(at function arguments)
I know that I am doing that wrong as I need to pass the template argument and the function arguments explicitly, but then this raises the question how is std::plus<>()
implemented so it skips the template and function arguments?
Upvotes: 0
Views: 208
Reputation: 36379
There are a number of issues in your code.
std::transform
), you need to pass them as constructor parameters to plus_clamp
. This then means that plus_clamp
needs to be a template rather than the operator.nl
is std::numeric_limits
it is a template so needs the template type passed to it: std::numeric_limits<T>::min()
std::plus<>()
just constructing the type and not calling its operator. It should be std::plus<>{}(lhs, rhs)
std::transform
you pass plus_clamp<>()
, in your original code plus_clamp
isn't a template so you just need plus_clamp()
.A fully working example would be:
#include <algorithm>
#include <functional>
#include <limits>
template<typename T = void>
struct plus_clamp {
constexpr plus_clamp(T MIN = std::numeric_limits<T>::min(),T MAX = std::numeric_limits<T>::max())
: MIN(MIN), MAX(MAX)
{
}
constexpr T operator()(const T& lhs, const T& rhs) {
T result = std::plus<>{}(lhs, rhs);
result = std::clamp(result, MIN,MAX);
return result;
}
T MIN;
T MAX;
};
int main()
{
std::vector<int> a,b, result;
std::transform(a.begin(),a.end(),b.begin(),result.begin(), plus_clamp<int>(10, 100));
}
If you are using c++17 you can use class template argument deduction and just use plus_clamp(10, 100)
.
Upvotes: 1
Reputation: 122298
Your plus_clamp
is not a template. Hence you need to remove the <>
:
std::transform(a.begin(),a.end(),b.begin(),result.begin(), plus_clamp())
// ^
std::plus<T>
on the other hand is a template. It has an operator()
:
constexpr T operator()( const T& lhs, const T& rhs ) const;
You can either explitly select the type to add via:
T result = std::plus<T>()(lhs,rhs);
//^ T == int in your example
//^ create instance
//^ call its operator()
or you use the default std::plus<>
which is std::plus<void>
. It has a operator()
that deduces the type from its parameters:
T result = std::plus<>()(lhs,rhs);
Upvotes: 1