Default argument in function template C++ - c++

Just to be sure, from what I've read and tried, I can't put a default argument in a function template correct? I've picked that much up both from my compiler AND from what other's have responded with... I'm asking because I'm a newb and some of the more technical responses are hard to understand. Is there a work around for this? I'm trying to create a findmax function that uses a default relational operator but with the option to overload...ie:
template <typename Type, typename Compare = std::less<Type> >
Type FindMax(std:vector<Type> &vec, Compare comp = Compare()) {
return *std::max_element(...
}
I suppose I could make a class for this but it seems like a lot of work when all I really want is one function... Thanks!
I should add another question as well about something that I've seen before:
What does this function tempate do, specifically, what is the (cmpFn)...) default argument doing?
template <typename ElemType>
ElemType FindMax(Vector<ElemType> &v, int (cmpFn)(ElemType, ElemType) = OperatorCmp)

There are a number of things to say:
What you defined is a function template, not a class template. Since you are using a default template parameter
typename Compare = std::less<Type>
I presume you are already using C++11, because for all I know function templates did not allow default template parameters in the previous versions of the standard.
On the other hand, default arguments of template parameters like this
Compare comp = Compare()
were possible in the previous version of the standard, too. Your statement that default arguments are not possible for templated parameters is wrong (or perhaps it actually referred to what I called default template parameters above).
The compiler error messages that you receive must be due to some other problem. Perhaps the Type you end up using does not go well with std::less, or the Compare type you use does not implement the default constructor. In any case, the following program compiles on GCC 4.6.2 (note that I changed the std::vector<> & to const std::vector<> & because that seemed more right):
#include <vector>
#include <functional>
#include <algorithm>
template <typename Type, typename Compare = std::less<Type> >
Type FindMax(const std::vector<Type> &vec, Compare comp = Compare()) {
return *std::max_element(vec.begin(),vec.end(),comp);
}
int main() {
FindMax(std::vector<int>());
return 0;
}
And indeed this requires the -std=C++0x option, but that is because the default template parameter, not the default argument.
About the extra question related to cmpFn:
That declares a function parameter, i.e. an argument that is itself a function. The declaration
int (cmpFn)(ElemType, ElemType)
means the local name of the function is cmpFn, its return type is int, and it takes two arguments, both of type ElemType. The idea is that the caller can pass a function (or a functor) that will then be used to compare the elements of the vector. E.g. if you define the default value of that argument OperatorCmp before the function declaration like this:
int OperatorCmp(int a, int b) {
return (a<b?-1:(a>b?1:0));
}
the declaration becomes valid and you can use it to find the maximum value of a std::vector<int>.

You can do that in C++11. As of C++03 you can easily work around it by creating two overloads with different number of arguments and forwarding from one to the other.
template <typename Type>
Type findMax( std::vector<Type> const & v ) {
return findMax( v, std::less<Type>() );
}
Alternatively you can use the standard algorithms and avoid having to write your own.

Related

Why is no deduction for template parameters only used as return type?

If I do not use tempate parameter (type) in a function argument list -> only as return type, then there is no deduction:
template <typename T>
T zero() { return 0; }
int main()
{
int x = zero();
}
gives:
a.cpp:15:18: error: no matching function for call to ‘zero()’
int x = zero();
^
a.cpp:11:3: note: candidate: ‘template<class T> T zero()’
T zero() { return 0; }
^~~~
a.cpp:11:3: note: template argument deduction/substitution failed:
a.cpp:15:18: note: couldn't deduce template parameter ‘T’
int x = zero();
The only way to compile, is to specify the template type in angle brackets:
template <typename T>
T zero() { return 0; }
int main()
{
int x = zero<int>();
}
So my question is, why g++ can deduce the type from argument list of template function, but cannot deduce it from return type (which is also known for compiler when compiling main, so it knows the type).
providing the type in angle brackets for template function is then arbitrary (because of deduction), when the template function uses template types in its argument list? So as a good practise, should I always provided the type in curly braces, no matter how the function is declared?
The second question is not readable much. Put it in simple words -> should I use foo<T>(arg, ...) (provide the type) everytime, no matter the function declaration? Even if it can be deduced by the compiler, but I will provided the type anyway for good practise?
Generally it is not possible to deduce function based on its return type. But if you use automatic types conversion c++ feature then you could achieve what you need:
template <typename T>
T zero() { return 1; }
template <>
float zero<float>() { return 3.0f; }
struct Zero
{
template<typename T>
operator T()
{
return zero<T>();
}
};
int main()
{
int x = Zero();
float y = Zero();
return x + y;
}
First you create temporary object Zero(), and during assigment we use conversion operator to execute correct specialization of zero template function.
So my question is, why g++ can deduce the type from argument list of template function
GCC follows the rules set forth by the C++ standard.
should I use foo(arg, ...) (provide the type) everytime, no matter the function declaration?
That depends on what you want to achieve. If you want to be explicit, do so. That would be similar to calling a foo_T() function in C which does not have templates nor overloads. However, if you want your code to be generic (for instance, because it is called in a template itself or because you want it easier to change on future type changes), then you would prefer to avoid writing the type explicitly.
Another option is using overloading rather than a template. Which one you use, again, depends on what you want and your use case.
Finally, you can also use auto instead:
auto zero() { return 0; }
Having said that, for signatures/interfaces, I think the best is to use explicit types everywhere unless there is a reason not to (e.g. it needs to be a template):
int zero() { return 0; }
Question 1
While it might be relatively easy to modify rules in yout trivial cases, this is not the case generally.
Consider a case like that:
template <A, B, C> A f(B b, C c) { ... } // #1
int f(int a, int b) { ... } // #2
int f(int a, double b) { ... } // #3
And a call like that:
double x = f(1, 2.0); // Call #1 or #3?
Thus it is not always trivial to modify rules and ensure that existing code continue to works. Such changes could easily lead to ambiguities, silent change of function being called...
Standard usually avoid modifying language in a way that could make unexpected silent changes (or make legal code become ambiguous).
However, it could be nice if there was a way to specify that we want deduction for return type in specific cases. By using a contextual keyword, rules could be defined on how to handled cases like the above one. For example, it could be a conflict if using return type deduction prefer an overload that is not the same one as without return type deduction.
Question 2
No, you should not generally provide the type if not needed.
Alternatives
While the solution to returns an object of a class with conversion operators could works, in may cases, them simplest solution would be to change the return value for an output parameter.
template <class T> void zero(T &t) { t = 0; } // set_zero would be more readable
int x;
zero(x);
I would not consider that solution appropriate for that case as the following is much clearer:
auto x = zero<int>();
In practice, given that the default value is zero for numerical types and for most other types, then cannot be initialized from an integer or it might not have the intended result, it would be better to simply write:
int x = {};
or
int x {};
It wouldn't have been impossible to define language rules to satisfy this case, but it would have been non-trivial and completely pointless.
This function has no business being a template, when all the information needed to decide its template argument is in the function. It should just return int, period. If you don't want to spell out the return type for whatever reason, this is what auto is for: it'll perform the deduction you seek.
On the other hand, if you want the 0 to be converted to different types for you depending on the template argument, then that makes more sense, and you already have the solution to that: provide the template argument (how could the computer guess it?). In this particular example you'd be better off just converting at the callsite, but presumably you have some more complex logic in mind.
As for whether you should always give template arguments explicitly, even when they are deducible, I'd say this is to some degree a matter of style. On the other hand it seems pretty pointless and noisy, but on the other it can be self-documenting and ensure that you're invoking the specialisation that you think you're invoking. So I think that this is going to depend on context.

Conflicting types for variadic parameter

I am trying to write a general invocation function.
It has the following syntax:
template<int Index, typename ReturnType, typename... Parameter>
ReturnType invokeGlobalFunction(Parameter... parameters)
{
return invocator->invoke<ReturnType>(Index, parameters...);
}
Next, I try to derive two different function points from it, like this:
registerFunction(::someGlobalFunction, &invokeGlobalFunction<0, void>);
registerFunction(::someOtherFunction, &invokeGlobalFunction<1, int>);
Where someGlobalFunction has the prototype void someGlobalFunction() and someOtherFunction has the prototype int someOtherFunction(int, const char *).
On the first call, it works like a charm, however the second call throws the error: candidate template ignored: deduced conflicting types for parameter 'Parameter' (<int, const char *> vs. <>).
This implies, that the compiler (g++ 7.4.0 on an Ubuntu system btw.) does not overload the invokeGlobalFunction with the different parameter sets like I expected him to.
A note: When I explicitly set the parameter types on the call
registerFunction(::someOtherFunction, &invokeGlobalFunction<1, int, int, const char *>);
the compiler happily takes it, but I'd like to avoid that, if possible.
As a bonus, it would be great, if I could somehow create a unique function each time the index changes, because that would allow me to have functions with identical parameters but differing return types (which is illegal as far as I know).
Thank you.
but I'd like to avoid that, if possible.
Not with template functions, as far I know.
The problem is that a template parameter isn't a single object but a set of object where a function can accept only an object from the set.
When you write
&invokeGlobalFunction<1, int>
you choose a precise function with Index = 1, ReturnType = int and (this is the point) an empty Parameter... list.
Suggestion: if you can, transform invokeGlobalFunction() in a template struct with a template method.
Something as
template <int Index, typename ReturnType>
struct invokeStruct
{
template <typename ... Parameters>
ReturnType operator() (Parameters ... parameters)
{
// ...
}
};
This way you have a set of struct with, in every struct, a set of operator() in it; passing a invokeStruct<1, int>{} as argument, you pass a single object but, inside it, you have available a set of method.

how to use template alias to remove one unecessary parameter

I have this template class:
template<typename T, T F(const std::string&)>
struct Builder
{
T operator()(const std::string& s) const { return F(s); }
typedef T type;
};
since I need a class holding a function and the value returned by the function (since I need a reference to it).
As you can see I have two template parameters, but actually the first is redundant. Is is possible to remove it in some way? Template alias? Something better than a macro
Return type T of the second template parameter must be defined before its first usage anyway (as the C++ rule states that any entity can be used only after its declaration), and the only way to declare is to use preceding type template parameter (as you did), so you cannot omit the first parameter.

Why is this Template Class Not Compiling?

So I have the following bit of code:
template <typename Type>
class Delegate
{
public:
Delegate(Type x)
{
}
};
void Method()
{
}
int main()
{
Delegate d(&Method);
return 0;
}
My question is: why can't the compiler deduce the template type based on what's passed into the constructor? The compile error I get is: Argument list for class template Delegate is missing. I understand that, but I thought type inference could overcome this to allow for cleaner syntax.
Because template parameter deduction only applies to functions. Class templates require parameters explicitly, always.
That's why many templates have a "named constructor" a function that simply constructs a temporary instance, but by virtue of being a function template rather than class template deduces parameters. For example std::make_pair.
C++11 introduced this new meaning of auto that actually allows you to deduce type of variable. So if you have C++11, you can create a "named constructor" for your class, like:
template <typename Type>
Delegate<Type> delegate(Type x) { return Delegate<Type>(x); }
and you can create a variable of deduced type with it like:
auto d = delegate(&Method);
Note, that this deduces d to be exactly the type returned by the initializer (you can have auto & or auto && if you want, but not much beyond that). This is way easier than trying to deduce hypothetical Delegate d(&Method), because that would involve cyclical dependency between deducing the type depending on overload resolution between constructors and the set of viable constructors depending on the deduced type (remember, constructors can be overloaded and types can be partially specialized).
It's for the same reason that this won't work:
// attempt to create a std::vector<std::string> of ten "x" strings:
std::vector v(10, "x");
In fact, it should result in the very same error message.
Use something like this to use type deduction:
template <class Type>
Delegate<Type> MakeDelegate(Type const &x)
{
return Delegate<Type>(x);
}
Or just do as you'd do with a std::vector and declare the type explictly.
By the way, main must return int, and arguments of unknown type (i.e. in templates) should be passed with const&.

What is angle brackets for argument values, and what is it used for? [duplicate]

This question already has answers here:
Reason for using non-type template parameter instead of regular parameter?
(6 answers)
Closed 4 years ago.
I am used to angle brackets being used to specify a type, as a parameter:
vector<int> vecOfInts ;
But in rapidjson, there is code like this:
document.Parse<0>(json) ;
The document.Parse method's signature is:
template <unsigned parseFlags>
GenericDocument& Parse(const Ch* str) {
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
GenericStringStream<Encoding> s(str);
return ParseStream<parseFlags>(s);
}
I didn't know you could pass a value inside angle brackets - thought angle brackets were used for typenames alone.
What is the code here doing, and why is he passing a value in the angle brackets?
Is this a good idea? When?
There are two different factors going on here.
First, it's possible to define templates that are parameterized over things other than just types. For example, here's a simple array type:
template <typename T, size_t N> struct Array {
T arr[N];
};
We can use this like
Array<int, 137> myArray;
We know that vector<int> and vector<double> are different types. But now we must also point out that Array<int,137> and Array<int,136> are different types.
Second, when using templates, the compiler has to be able to figure out a value for all of the template arguments. When you're using template classes, this is why you typically specify all the template arguments. You don't say vector x, for example, but instead say something like vector<double> x. When using template functions, most of the time the compiler can figure out the arguments. For example, to use std::sort, you just say something like
std::sort(v.begin(), v.end());
However, you could also write
std::sort<vector<int>::iterator>(v.begin(), v.end());
to be more explicit. But sometimes, you have a template function for which not all the arguments can be figured out. In your example, we have this:
template <unsigned parseFlags>
GenericDocument& Parse(const Ch* str) {
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
GenericStringStream<Encoding> s(str);
return ParseStream<parseFlags>(s);
}
Notice that the parseFlags template parameter can't be deduced from just the arguments of the function. As a result, to call the function, you must specify the template parameter, since otherwise the compiler can't figure it out. That's why you'd write something like
Parse<0>(myString);
Here, the 0 is a template argument (resolved at compile-time), and myString is the actual argument (resolved at run-time).
You can actually have methods that combine a bit of type inference and a bit of explicit type parameters. For example, in Boost, there's a function lexical_cast that can do conversions to and from string types. The function signature to convert from a non-string type to a string type is
template <typename Target, typename Source>
Target lexical_cast(const Source& arg);
Here, if you call lexical_cast, the compiler can figure out what Source is, but it can't deduce Target without some hints. To use lexical_cast, therefore, you'd write something like
std::string myString = boost::lexical_cast<std::string>(toConvertToString);
More generally, the compiler says that you have to specify some number of template arguments (optionally 0), and it will try to deduce the rest. If it can, great! If not, it's a compile-time error. Using this, if you'd like, you could write a function like
template <int IntArgument, typename TypeArgment>
void DoSomething(const TypeArgument& t) {
/* ... */
}
To call this function, you'd have to invoke it like this:
DoSomething<intArg>(otherArg);
Here, this works because you have to explicitly tell the compiler what IntArgument is, but then the compiler can deduce TypeArgument from the type of the argument to DoSomething.
Hope this helps!