Why I can't use std::string in C++ template? [duplicate] - c++

I am implementing a sorting algorithm as personal training (no homework!).
I have the following code (excluding imports etc.):
template<class RandomIt, class Compare>
void sort(RandomIt first, RandomIt last, Compare comp)
{
/* actual sorting code is here */
}
template<class RandomIt>
void sort(RandomIt first, RandomIt last)
{
std::function<bool(decltype(*first), decltype(*last))> comp = [](decltype(*first) a, decltype(*last) b)
{
return a < b;
};
sort (first, last, comp);
}
Trying to call this code with a test array
auto test_array_1 = std::make_unique <std::array < uint64_t,SORTING_TEST_LENGTH >> ();
std::copy(std::cbegin(*template_array), std::cend(*template_array), std::begin(*test_array_1));
sort(std::begin(*test_array_1), std::end(*test_array_1));
The compiler complains about "ambiguous call to overloaded function" (VC++ C2668). From my understanding the call should not be ambiguous though. Also giving the call in the second sort function the template parameters for the first sort function does not have any effect.
What am I missing here? Why does the compiler consider the second call "ambiguous"?

The problem is two fold.
First, sort is found via ADL, so you get two overloads, and they both match. In general, naming functions the same as std functions when you are not trying to ADL-overload is fraught, due to the possibility of ADL-induced ambiguity.
Now, this only happens when passing types from namespace std; Sometimes iterators are from this namespace, but not in this case : array uses raw pointer iterators. The trigger for ADL finding std::sort is the std::function.
Which brings me to the next problem: there is very little to be gained, and much to be lost, by std::function in the above code. Replace it with auto. Pass low level sorting algorithms an inlineable comparison object.
You still do not want to call it sort. If you call it sort you need to qualify calls with the namespace, or (sort) to block ADL.
The ADL rule is that both the "usual" functions, and functions in the namespace of arguments, and namespace of what arguments point to, and template arguments of arguments, etc, are considered for overload resolution. This is Argument Dependent Lookup, or ADL, or Koenig lookup. It means that namespace pollution of a kind can occur when using types from another namespace (which is sad), but it also makes some nice magic happen (like std::cout << "hello world\n";`)

Related

template programming: ambiguous call to overloaded function

I am implementing a sorting algorithm as personal training (no homework!).
I have the following code (excluding imports etc.):
template<class RandomIt, class Compare>
void sort(RandomIt first, RandomIt last, Compare comp)
{
/* actual sorting code is here */
}
template<class RandomIt>
void sort(RandomIt first, RandomIt last)
{
std::function<bool(decltype(*first), decltype(*last))> comp = [](decltype(*first) a, decltype(*last) b)
{
return a < b;
};
sort (first, last, comp);
}
Trying to call this code with a test array
auto test_array_1 = std::make_unique <std::array < uint64_t,SORTING_TEST_LENGTH >> ();
std::copy(std::cbegin(*template_array), std::cend(*template_array), std::begin(*test_array_1));
sort(std::begin(*test_array_1), std::end(*test_array_1));
The compiler complains about "ambiguous call to overloaded function" (VC++ C2668). From my understanding the call should not be ambiguous though. Also giving the call in the second sort function the template parameters for the first sort function does not have any effect.
What am I missing here? Why does the compiler consider the second call "ambiguous"?
The problem is two fold.
First, sort is found via ADL, so you get two overloads, and they both match. In general, naming functions the same as std functions when you are not trying to ADL-overload is fraught, due to the possibility of ADL-induced ambiguity.
Now, this only happens when passing types from namespace std; Sometimes iterators are from this namespace, but not in this case : array uses raw pointer iterators. The trigger for ADL finding std::sort is the std::function.
Which brings me to the next problem: there is very little to be gained, and much to be lost, by std::function in the above code. Replace it with auto. Pass low level sorting algorithms an inlineable comparison object.
You still do not want to call it sort. If you call it sort you need to qualify calls with the namespace, or (sort) to block ADL.
The ADL rule is that both the "usual" functions, and functions in the namespace of arguments, and namespace of what arguments point to, and template arguments of arguments, etc, are considered for overload resolution. This is Argument Dependent Lookup, or ADL, or Koenig lookup. It means that namespace pollution of a kind can occur when using types from another namespace (which is sad), but it also makes some nice magic happen (like std::cout << "hello world\n";`)

choose which constructor in c++

I am practicing C++ by building my own version of vector, named "Vector". I have two constructors among others, fill constructor and range constructor. Their declarations look like following:
template <typename Type>
class Vector {
public:
// fill constructor
Vector(size_t num, const Type& cont);
// range constructor
template<typename InputIterator> Vector(InputIterator first, InputIterator last);
/*
other members
......
*/
}
The fill constructor fills the container with num of val; and the range constructor copies every value in the range [first, last) into the container. They are supposed to be the same with the two constructors of the STL vector.
Their definitions goes following:
//fill constructor
template <typename Type>
Vector<Type>::Vector(size_t num, const Type& cont){
content = new Type[num];
for (int i = 0; i < num; i ++)
content[i] = cont;
contentSize = contentCapacity = num;
}
// range constructor
template <typename Type>
template<typename InputIterator>
Vector<Type>::Vector(InputIterator first, InputIterator last){
this->content = new Type[last - first];
int i = 0;
for (InputIterator iitr = first; iitr != last; iitr ++, i ++)
*(content + i) = *iitr;
this->contentSize = this->contentCapacity = i;
}
However, when I try to use them, I have problem distinguishing them.
For example:
Vector<int> v1(3, 5);
With the this line of code, I intended to create a Vector that contains three elements, each of which is 5. But the compiler goes for the range constructor, treating both "3" and "5" as instances of the "InputIterator", which, with no surprises, causes error.
Of course, if I change the code to:
Vector<int> v1(size_t(3), 5);
Everything is fine, the fill constructor is called. But that is obviously not intuitive and user friendly.
So, is there a way that I can use the fill constructor intuitively?
You can use std::enable_if (or boost::enable_if if you don't use C++11) to disambiguate the constructors.
#include <iostream>
#include <type_traits>
#include <vector>
using namespace std;
template <typename Type>
class Vector {
public:
// fill constructor
Vector(size_t num, const Type& cont)
{
cout << "Fill constructor" << endl;
}
// range constructor
template<typename InputIterator> Vector(InputIterator first, InputIterator last,
typename std::enable_if<!std::is_integral<InputIterator>::value>::type* = 0)
{
cout << "Range constructor" << endl;
}
};
int main()
{
Vector<int> v1(3, 5);
std::vector<int> v2(3, 5);
Vector<int> v3(v2.begin(), v2.end());
}
The above program should first call the fill constructor by checking if the type is an integral type (and thus not an iterator.)
By the way, in your implementation of the range constructor, you should use std::distance(first, last) rather than last - first. Explicitly using the - operator on iterators limits you to RandomAccessIterator types, but you want to support InputIterator which is the most generic type of Iterator.
Even std::vector seems to have this issue.
std::vector<int> v2(2,3);
chooses
template<class _Iter>
vector(_Iter _First, _Iter _Last)
In Visual C++, even though it should match closer to the non templated case..
Edit: That above function (correctly) delegates the construction to the below one. I am totally lost..
template<class _Iter>
void _Construct(_Iter _Count, _Iter _Val, _Int_iterator_tag)
Edit #2 AH!:
Somehow this below function identifies which version of the constructor is meant to be called.
template<class _Iter> inline
typename iterator_traits<_Iter>::iterator_category
_Iter_cat(const _Iter&)
{ // return category from iterator argument
typename iterator_traits<_Iter>::iterator_category _Cat;
return (_Cat);
}
The above shown _Construct function has (atleast) 2 versions overloading on the third variable which is a tag to returned by the above _Iter_cat function. Based on the type of this category the correct overload of the _Construct is picked.
Final edit:
iterator_traits<_Iter> is a class that seems to be templated for many different common varieties, each returning the appropriate "Category" type
Solution: It appears template specialization of the first arguement's type is how the std library handles this messy situation (primitive value type) in the case of MS VC++. Perhaps you could look into it and follow suit?
The problem arises (I think) because with primitive value types, the Type and size_t variables are similar, and so the template version with two identical types gets picked.
The problem is the same at the one faced by the standard library implementation. There are several ways to solve it.
You can meticulously provide non-template overloaded constructors for all integral types (in place of the first parameter).
You can use SFINAE-based technique (like enable_if) to make sure the range constructor is not selected for integer argument.
You can branch the range constructor at run-time (by using if) after detecting integral argument (by using is_integral) and redirect control to the proper constructing code. The branching condition will be a compile-time value, meaning that the code will probably be reduced at compile-time by the compiler.
You can simply peek into your version of standard library implementation and see how they do it (although their approach is not required to be portable and/or valid from the point of view of abstract C++ language).
This ambiguity caused problems for early library implementers. It's called the "Do The Right Thing" effect. As far as I know, you need SFINAE to solve it… it might have been one of the first applications of that technique. (Some compilers cheated and hacked their overload resolution internals, until the solution was found within the core language.)
The standard specification of this issue is one of the key differences between C++98 and C++03. From C++11, §23.2.3:
14 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.
15 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.

Can iter_swap be specialised?

If I have a container std::vector<T*> items, I can create an IndirectIterator which wraps std::vector<T*>::iterator and allows iterating over T's rather than T*'s.
Can I specialise iter_swap for IndirectIterator to make standard algorithms (such as std::sort) swap items by pointer?
i.e., if I write the following, will it have any effect on standard algorithms?
namespace some_namespace
{
template <typename IterT>
class IndirectIterator
{
IterT m_base;
public:
typedef IterT base_iterator;
typedef /* ... */ reference;
/* ... */
reference operator*() const { **m_base; }
const base_iterator& base() const { return m_base; }
base_iterator& base() { return m_base; }
};
template <typename T>
void iter_swap(IndirectIterator<T>& a, IndirectIterator<T>& b)
{
using std::iter_swap;
iter_swap(a.base(), b.base());
}
}
The benefit of this specialisation is that it swaps pointers rather than full T instances, so it's faster (potentially).
As far as I can see, iter_swap is only used in std::reverse, and it does not mention any kind of argument-dependent lookup: it always uses std::iter_swap. And since you are not allowed to overload functions in the std namespace, you're out of luck.
Can I specialise iter_swap for IndirectIterator to make standard
algorithms (such as std::sort) swap items by pointer?
You can always make your overload/specialization. However your question is whether you can specialize iter_swap inside the namespace std.
I think the answer is unclear from the standard.
I have found that in some cases, I had to define a special iter_swap inside std so that std::sort uses it. In gcc std lib std::sort uses the qualified std::iter_swap.
This is probably a defect in std::sort.
IMO std::sort should call an unqualified swap_iter.
i.e., if I write the following, will it have any effect on standard
algorithms?
Not in GCC (at least) because standard algorithms use qualified std::iter_swap (bug?)
I don't think the standard is clear about it.
You are allowed to reopen std namespace and specialize templates inside std as long as you specialize them for user-defined types. In your case you can actually specialize std::iter_swap for your purposes, just make sure you are doing it in std namespace, not in your own namespace (as in your example). It is not very elegant, but it is allowed.
Starting in C++20, the answer is unambiguously "yes, you can customize your own ADL iter_swap." STL algorithms should use it, but aren't required to, and there is implementation divergence in practice.
For customizing a customization point, you should use the "hidden friend idiom":
namespace some_namespace {
template <class IterT>
class IndirectIterator {
IterT m_base;
public:
/* ... */
reference operator*() const { return **m_base; }
const base_iterator& base() const { return m_base; }
// "It's not a member, it's just a friend"
friend void iter_swap(IndirectIterator a, IndirectIterator b) {
using std::iter_swap;
iter_swap(a.base(), b.base());
}
};
}
Subtle change here: your iter_swap had been taking its arguments by mutable reference! That wouldn't work, e.g. if it were passed an IndirectIterator that was const, or that was an rvalue. Iterator parameters should always be taken by value. Similarly, there's no sense in providing a non-const version of base(). Your base() is a getter, not a setter; it should be a const member function for the same reason vector::size() is a const member function.
Finally, the big caveat here is that you must never customize iter_swap to do anything observably different from swapping the targets of the iterators. If you do that, then it's undefined behavior — all bets are off — the program could do anything. Formally, this requirement is given in [iterator.cust.swap]:
If the [iter_swap] function selected by overload resolution does not exchange the values denoted by E1 and E2, the program is ill-formed, no diagnostic required.
I believe your idea of having iter_swap swap the "first-level" targets rather than the "second-level" targets is perfectly kosher, as long as you're never going to rely on observing the difference. The standard library is still allowed to bypass iter_swap and just do swap(*it, *kt) if it feels like it; your code must be able to cope with that, or else "the program is ill-formed, no diagnostic required." (I.e., you must fully commit to the idea that swapping those first-level targets is tantamount to "exchanging the values of E1 and E2," and thus interchangeable with any other method of exchanging the values. You can't rely on your own method getting used.)
Here is a complete C++20 example on Godbolt. As of February 2023, here's where I see the customized iter_swap actually getting used:
Algorithm
libstdc++
libc++
Microsoft
std::ranges::partition
Yes
Yes
Yes
std::ranges::sort
No
No
Yes
std::partition
No
No
No
std::sort
No
No
No

Wrapper contains() function for different containers

Inspired by contains(), I want do declare contains(), fitting misc containers.
// for std::vector, std::list, .. (1)
template<typename C, typename T>
bool contains(const C& container, const T& val)
{
return ::std::find(container.begin(), container.end(), val) != container.end();
}
// partial specialization for std::map (2)
template<typename K, typename V>
bool contains(const ::std::map<K, V>& container, const K& key)
{
// std::map.find() is better than std::find used in (1)
return container.find(key) != container.end();
}
Following question, I want to add the functions to namespace the arguments belongs too.
Questions:
Types of val from (1) and key from (2) are unknown. Does it mean I don't need to put the functions to any namespace or do I need to put them in std namespace, the containers belong to?
Is it possible to improve (2) it will preferred by compiler than (1) for std::map, std::set, boost::unordered_map, boost::unordered_set?
boost::algorithm::contains(). Do I need choose another name for my wrapper?
(1) Don't add anything to the std namespace
(2) As Space_C0wb0y points out, (2) is not a partial specialization, but an overload. I'm not sure if this is standard behaviour, but on VS2008 this is resolved correctly (the overloaded version is used for map). In either case, I think a slighly better version would be:
template<typename C>
bool contains(const C & mapContainer, const typename C::key_type & key)
{
// std::map.find() is better than std::find used in (1)
return mapContainer.find(key) != mapContainer.end();
}
This is a partial specialization (T is specialized to C::key_type) and would work for all types that has the key_type typedef (e.g. std::map, boost::unordered_map etc.)
(3) Put in separate namespace (see #Tony's answer)
Sidenote: I'm not sure I think these functions should have the same name. If I saw a function contains() accepting a map + another argument I could think that (1) the function checks if the map contains an entry for the given value (e.g. some key has the value provided) or (2) the function checks if there is such an entry in the map (e.g. the provided value is a pair). Instead I would call the function contains_key() for maps.
Edit:
After a bit of checking I suspect that the code above isn't compliant as it uses "template typedefs". This is not a standard C++ feature, but it seems that Visual Studio supports it in some cases. There's probably a workaround for this, but not one I'm clever enough to come up with now.
On number 3. you should place your version of contains in it's own namespace to avoid naming clashes. That's the purpose of namespaces.
Yes, keep them in a separate namespace.
The only thing to place in the same namespace as the argument type is operator overloads, to allow for Koenig (argument-dependent) lookup. These are not overloaded operators. End of story.
Note how this also answer question 2.: how you make the compiler prefer your implementations:
using myownversions::contains;
(assuming you named your namespace myownversions for now)
You must not put them into the std namespace. This is forbidden. You can put them into any namespace you like.
There is probably some SFINAE-magic you can do there, but I cannot come up with it in my own.
See #Tony's answer.

Ambiguous call to templated function due to ADL

I've been bitten by this problem a couple of times and so have my colleagues. When compiling
#include <deque>
#include <boost/algorithm/string/find.hpp>
#include <boost/operators.hpp>
template< class Rng, class T >
typename boost::range_iterator<Rng>::type find( Rng& rng, T const& t ) {
return std::find( boost::begin(rng), boost::end(rng), t );
}
struct STest {
bool operator==(STest const& test) const { return true; }
};
struct STest2 : boost::equality_comparable<STest2> {
bool operator==(STest2 const& test) const { return true; }
};
void main() {
std::deque<STest> deq;
find( deq, STest() ); // works
find( deq, STest2() ); // C2668: 'find' : ambiguous call to overloaded function
}
...the VS9 compiler fails when compiling the second find. This is due to the fact that STest2 inherits from a type that is defined in boost namespace which triggers the compiler to try ADL which finds boost::algorithm::find(RangeT& Input, const FinderT& Finder).
An obvious solution is to prefix the call to find(…) with "::" but why is this necessary? There is a perfectly valid match in the global namespace, so why invoke Argument-Dependent Lookup? Can anybody explain the rationale here?
ADL isn't a fallback mechanism to use when "normal" overload resolution fails, functions found by ADL are just as viable as functions found by normal lookup.
If ADL was a fallback solution then you might easily fall into the trap were a function was used even when there was another function that was a better match but only visible via ADL. This would seem especially strange in the case of (for example) operator overloads. You wouldn't want two objects to be compared via an operator== for types that they could be implicitly converted to when there exists a perfectly good operator== in the appropriate namespace.
I'll add the obvious answer myself because I just did some research on this problem:
C++03 3.4.2
§2 For each argument type T in the function call, there is a set of zero or more associated namespaces [...] The sets of namespaces and classes are determined in the following way:
[...]
— If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a
member, if any; and its direct and indirect base classes. Its associated namespaces are the namespaces
in which its associated classes are defined.
§ 2a If the ordinary unqualified lookup of the name finds the declaration of a class member function, the associated
namespaces and classes are not considered. Otherwise the set of declarations found by the lookup of
the function name is the union of the set of declarations found using ordinary unqualified lookup and the set
of declarations found in the namespaces and classes associated with the argument types.
At least it's standard conformant, but I still don't understand the rationale here.
Consider a mystream which inherits from std::ostream. You would like that your type would support all the << operators that are defined for std::ostream normally in the std namespace. So base classes are associated classes for ADL.
I think this also follows from the substitution principle - and functions in a class' namespace are considered part of its interface (see Herb Sutter's "What's in a class?"). So an interface that works on the base class should remain working on a derived class.
You can also work around this by disabling ADL:
(find)( deq, STest2() );
I think you stated the problem yourself:
in the global namespace
Functions in the global namespace are considered last. It's the most outer scope by definition. Any function with the same name (not necessarily applicable) that is found in a closer scope (from the call point of view) will be picked up first.
template <typename Rng, typename T>
typename Rng::iterator find( Rng& rng, T const& t );
namespace foo
{
bool find(std::vector<int> const& v, int);
void method()
{
std::deque<std::string> deque;
auto it = find(deque, "bar");
}
}
Here (unless vector or deque include algorithm, which is allowed), the only method that will be picked up during name look-up will be:
bool foo::find(std::vector<int> const&, int);
If algorithm is somehow included, there will also be:
template <typename FwdIt>
FwdIt std::find(FwdIt begin, FwdIt end,
typename std::iterator_traits<FwdIt>::value_type const& value);
And of course, overload resolution will fail stating that there is no match.
Note that name-lookup is extremely dumb: neither arity nor argument type are considered!
Therefore, there are only two kinds of free-functions that you should use in C++:
Those which are part of the interface of a class, declared in the same namespace, picked up by ADL
Those which are not, and that you should explicitly qualified to avoid issues of this type
If you fall out of these rules, it might work, or not, depending on what's included, and that's very awkward.