C++ std::find() and template parameter - c++

In C++ reference, the find method is defined as
template <class InputIterator, class T>
InputIterator find (InputIterator first, InputIterator last, const T& val);
However, when I use find method, I use find() method without explicitly describing the InputIterator and T.
For example, I use
std::vector<T> aList
...
std::list<int>::iterator pointer = std::find(aList.begin(), aList.end(), *it);
not this
std::list<int>::iterator pointer = std::find<std::list<int>::iterator, int>(aList.begin(), aList.end(), *it);
How does it work? Why don't I need to specify the types when I use find method?

It's called argument type deduction. From the C++ Standard (C++11 version):
(§14.8.2/1) When a function template specialization is referenced, all of the template arguments shall have values. The values can be explicitly specified or, in some cases, be deduced from the use or obtained from default
template-arguments. [ Example:
void f(Array<dcomplex>& cv, Array<int>& ci) {
sort(cv); // calls sort(Array<dcomplex>&)
sort(ci); // calls sort(Array<int>&)
}
and
void g(double d) {
int i = convert<int>(d); // calls convert<int,double>(double)
int c = convert<char>(d); // calls convert<char,double>(double)
}
— end example ]
Type deduction is only done when arguments are present, i.e. it only works for function templates, not for class templates (not even for the constructor).
Type deduction can cause very complicated ambiguities, especially when multiple template specializations and/or overloaded function definitions are given. In some cases, it won't be possible, and then you must specify some or all of the template arguments explicitly using the angle-bracket syntax.

Because the types are deduced. The compiler can look at the call, and figure out that since you're passing a value aList.begin(), the iterator will have the type that is the return type of aList.begin(). Similarly with using *it - the compiler knows what type *it is, hence can deduce the type being passed in as a function argument.

Related

Why do std::forward_list::remove and std::erase<std::forward_list> have different types for value?

std::forward_list has a member function:
size_type remove(const T& value);
and a non-member function std::erase declared as follows:
template<class T, class Alloc, class U>
typename forward_list<T, Alloc>::size_type
erase(forward_list<T, Alloc>& c, const U& value);
Please note that non-member function std::erase has a different type U for value; while member function remove just use type T for value.
Why doesn't std::erase just use type T for value?
Is there any design rationale behind the inconsistent?
I can see a practical reason. And it has to do with the difficulties imposed by template argument deduction. Imagine this hypothetical function:
template<typename T>
void foo(std::forward_list<T> const&, T const&) {}
What do you get for this invocation?
std::forward_list<double> l;
foo(l, 1);
The answer is that you get an error in template argument deduction. According to one argument T is double, but according to the other it's int. If I was to write erase, I'd use two different template arguments as well, if only to avoid such issues in innocent code.
Now remove is not a member template, it is a regular member function of any specialization. So you can write, without problem:
std::forward_list<double> l;
// later
l.remove(1);
1 is an integer, it doesn't match the double that remove expects. However, that is not a problem. Because remove is a regular member function of a concrete specialization, and an implicit conversion is possible.
As it is pointed out on cppreference.com:
Unlike std::forward_list::remove, erase accepts heterogenous types and
does not force a conversion to the container's value type before
invoking the == operator.
So, for std::erase() it is enough to have operator== defined for T and U without imposing a restriction on U being convertible to T which gives more freedom comparing to remove() member function.

Extract type from subexpression in template

Given the following templated function:
template <typename T>
void f(std::function <void (T)>) {}
Can I extract T without having to explicitly mention it when calling f?
f<int>([](int){}); works fine but I'd like T to be deduced and f([](int){}); to just work. The latter errors out with "no matching function for call to".
You can deduce T if the object passed into the function actually has type std::function<void(T)>. If the type you pass in is a lambda, then you'll have to deduce it from the type of the lambda's function call operator, like so:
template <class Callable, class Arg, class T>
void f_helper(Callable callable, Ret (Callable::*)(T)) {
// do something with T
}
template <class Callable>
void f(Callable callable) {
f_helper(callable, &callable::operator());
}
Actually, in reality it is a bit more annoying than this, because you need at least two overloads for f_helper, according to whether the lambda is declared mutable (which determines whether operator() is const), and in C++17 you also need to double the number of overloads again according to whether the lambda is noexcept.
The standard library sidesteps issues like this by not attempting to extract the argument type from the callables you pass to algorithms such as std::sort. It just accepts an arbitrary callable type and then tries to call it.

Can enable_if be used as a non-extra parameter (e.g. for a constructor)?

I am writing a new container, and trying to comply with N3485 23.2.3 [sequence.reqmts]/14, which states:
For every sequence container defined in this Clause and in Clause 21:
If the constructor
template <class InputIterator>
X(InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type())
is called with a type InputIterator that does not qualify as an
input iterator, then the constructor shall not participate in overload
resolution.
(/14 repeats this almost verbatim for the member functions taking iterator ranges)
N3485 23.2.3 [sequence.reqmts]/15 says:
The extent to which an implementation determines that a type cannot be an input iterator is unspecified, except that as a minimum integral types shall not qualify as input iterators.
My understanding is that the phrase "shall not participate in overload resolution" means that the container implementer is supposed to use SFINAE tricks to disable that constructor or member function during template argument deduction. For the member functions, this is no big deal; as the return type on a function is the normal way to use enable_if. But for the constructor, there is no return type on which enable_if can be applied. This was my first attempt to declare the constructor:
// The enable_if use below is to comply with 23.2.3 [sequence.reqmts]/14:
// ... is called with a type InputIterator that does not qualify as an input iterator
// then the constructor shall not participate in overload resolution.
template <typename InputIterator>
path(std::enable_if<!std::is_integral<InputIterator>::value, InputIterator>::type first,
InputIterator last, Allocator const& allocator = allocator_type());
However, boost's enable_if docs suggest using a dummy pointer parameter initialized to nullptr instead of using an actual parameter to a function. Is that necessary for correct behavior here or is the preceding declaration of path's iterator range constructor okay?
The Good Robot (R. Martinho Fernandes) discusses the issue with a clean C++11 solution, namely using a default template parameter to apply enable_if, in his blog.
However, let me just point out here that doing
template< class Type >
void foo( typename Something< Type >::T )
foils argument deduction.
It's still possible to call the function, by explicitly providing the template argument. But in C++ the compiler will simply refuse to match e.g. a MyType actual argument to formal argument type Something<Blah>::T, because while this can be done in some special cases it cannot always be done (there could be countless choices of Blah where Something<Blah>::T was MyType).
So, your current approach won't work in general, but the whole problem of the specification's requirement is a C++11 problem, so the C++11 specific solution is OK! :-)

C++ - Defining 2 template parameters but calling with only 1

While working on a project I came upon this code, which I'm trying to figure out:
enum Attributes { ACTIVE, COMPLETE, POSITION }
template<Attributes NN,typename TT>
TT& Set(TT&& t)
{
return typeList.get<NN>()=t; //typeList is a boost tuple
}
This is called later on with
object.Set<ACTIVE>(true);
There's only one template parameter in there!
How is possible to specify a template with two parameters, and then call it with only one? I would think the Set method supposed to take 2 template parameters (Attributes and typename), like an std::map.
The second one is deduced fom the type of argument passed to a function, in this case bool.
When calling a function template template parameters, which are the type of the function arguments can be automatically deduced from the type of the arguments, the function is called with:
object.Set<ACTIVE>(true); //same as object.Set<Active,bool>(true);
object.Set<ACTIVE>(5); //same as object.Set<Active,int>(5);
This is the reason one can use template functions from the standardlibrary, like std::max or std::copy without explicitely mentioning the types of the arguments.
Read this.
When a function template specialization is referenced, all of the
template arguments shall have values. The values can be explicitly
specified or, in some cases, be deduced from the use or obtained from
default template-arguments.
[ Example:
void f(Array<dcomplex>& cv, Array<int>& ci) {
sort(cv); // calls sort(Array<dcomplex>&)
sort(ci); // calls sort(Array<int>&)
}
and
void g(double d) {
int i = convert<int>(d); // calls convert<int,double>(double)
int c = convert<char>(d); // calls convert<char,double>(double)
}
—end example ]
and 14.8.2 par of this doc. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

Why can't my C++ compiler deduce template argument for boost function?

I define a method like so:
template <class ArgT>
void foo(ArgT arg, ::boost::function< void(ArgT) > func)
{
func(arg);
}
and use it like this --for instance--:
foo(2, [](int i) -> void { cout << i << endl; });
Why can't the compiler deduce the type since it's definitely an int?
I get 'void foo(ArgT,boost::function<void(ArgT)>)' : could not deduce template argument for 'boost::function<void(ArgT)>' from 'anonymous-namespace'::<lambda0>'.
While C++ lambdas are strictly monomorphic, they are merely shorthand for function objects (aka functors), and in general functors can be polymorphic; i.e., their call operators can be overloaded or templated. As a result, functors (and, consequently, lambdas) are never implicitly convertible to templated std::function<> (or boost::function<>) instances because functors' operator() argument types are not automatically inferable.
To phrase it slightly differently, the natural type of your lambda expression is a functor with a parameterless constructor and an operator() with the signature void operator ()(int) const. However obvious this fact may be to you and I, it's not automatically inferrable that ArgT should resolve to int because lambdas are functors and functors' operator()s are possible to overload and template.
TL;DR: What you want isn't possible.
You want a conversion from the lambda function to boost::function<void(ArgT)> where ArgT is to be deduced. As a general rule, you cannot have type deduction and conversion in the same argument of a function: no conversions take place when deducing a template parameter.
The reasoning behind this is as follows. There are three types involved here: (1) the template parameter, (2) the function parameter type, (3) the passed object type. Two of the types (1 and 2) can be deduced from one another, but both are unknown. If the compiler can assume 2 and 3 are the same type, the problem is solved, but if all the compiler knows is that 3 can be converted to 2 there could be any number of possible solutions, and the compiler is not expected to solve the problem. In practice we know that in this particular case there is only one possible solution, but the standard does not make a distinction between cases.
The rule above applies in all deducible contexts, even if the template parameter can be deduced from another function parameter. The solution here is make the relevant function parameter a non-deducible context, ie a context in which the compiler will never attempt to deduce the template parameter from the function parameter. This can be done as follows:
template <class T> struct identity { typename T type; };
template <class ArgT>
void foo(ArgT arg, typename identity<::boost::function<void(ArgT)>>::type func)
{
func(arg);
}