Reputation: 3
I have a problem using the transform function of the algorithm library in c++. I want to use it with a unary template function which means that my transform function would need 3 iterators and the function as arguments. However, my program crashes and the compiler tells me I'm missing an argument which makes no sense since my function is unary and not a binary operation.
My code is the following :
template <typename T>
T reciprocal ( T value )
{ return (T)1/value ; }
int main()
{
vector<int> vec(5, 2);
transform(vec.begin(), vec.end(), vec.begin(), reciprocal);
}
Is the use of templates with transform forbidden?
Upvotes: 0
Views: 1575
Reputation: 490088
Right now, you're depending on the compiler to deduce the correct type over which to instantiate reciprocal
, but since you haven't specified the parameter type, it can't do that.
You can get around that by specifying the correct type, as @jaunchopanza has already pointed out. By structuring the code a bit differently:
struct reciprocal {
template <typename T>
T operator()(T value)
{
return (T) 1 / value;
}
};
...you can get the compiler to deduce the type, so code like this:
std::transform(vec.begin(), vec.end(), vec.begin(), reciprocal());
...works correctly (though note the parens to create an instance of reciprocal
).
Of course, a reciprocal on int
s doesn't usually make much sense -- all it can ever produce is 0 or 1 (or undefined behavior for an input of 0). You probably want to use a floating point type to get meaningful results:
std::vector<double> vec(5, 2);
std::transform(vec.begin(), vec.end(), vec.begin(), reciprocal());
Upvotes: 0
Reputation: 227380
reciprocal
is a function template, and std::transform
cannot figure out which particular specialization to use. You need to be explicit and give it a template parameter:
transform(vec.begin(), vec.end(), vec.begin(), reciprocal<int>);
Note that in your case, you will be performing integer division 1/2
, which will give you a bunch of zeros. To illustrate a floating point reciprocal calculation, and the fact that the template parameter of reciprocal
need not be the same as the one used for vec
, you can try this:
std::vector<double> vec2;
std::transform(vec.begin(),
vec.end(),
std::back_inserter(vec2),
reciprocal<double>);
This will result in vec2
containing five 0.5
values.
Upvotes: 2
Reputation: 208323
but my program crashes and the compiler tells me im missing an argument which makes no sense since my function is unary and not a binary operation
You should clearly state whether your program compiles and then crashes, not compiles, the compiler crashes and what type of argument is missing.
Now guessing what you mean, the problem is that the transform
template does not place any restrictions on the last argument, so the compiler is not able to determine which of the overloads (specialization) of reciprocal
should be passed to the transform template. You can specify which one you want manually:
transform(vec.begin(), vec.end(), vec.begin(), &reciprocal<int>);
or may the use of templates with transform be forbidden?
This is an interesting point on itself in that it shows some common misunderstaning. A template
is a blueprint from which other elements are created. In this case you have a function template which is just a blueprint from which the compiler will generate different functions by replacing the template arguments. In any context where a function is needed, a function template cannot be used, although a specialization (i.e. a function generated from that function template) can be used.
This becomes slightly confusing in some contexts where you can use the name of the template to refer to a concrete specialization. Namely, inside a class template definition (or the definition of it's members), the name of the template can be used to refer to the specialization. In the case of function templates, the name of the template can be used to refer to all possible specializations of the function template in those contexts where the compiler will be able to discard all but one of those specializations, for example:
int call(int (*ptr)(int)) { return ptr(5); }
call(reciprocal); // [1]
In [1], reciprocal
refers to all possible specializations of the function template, but this particular use is allowed as only one of those specialiations (namely reciprocal<int>
) can be used as an argument to call
.
But those are the exceptions, the main point is that a class template or function template is not a class or function but a generator from which classes and functions can be created by the compiler.
Upvotes: 1