Why Do I Get a Template Error If I Name My Function 'Swap', But 'Swap' Is Okay

Why do I get a template error if I name my function `swap`, but `Swap` is okay?

This is because there already exists a function called swap. It is actually under the std namespace, but because you have a using namespace std line, it exists without the std:: prefix.

As you can see, using the using namespace std isn't always a good option because of possible name collisions, as in this example. In general one should prefer not to use the using directive unless there's a real reason for this - namespaces exist for a reason - to prevent name collisions.

Why is this swap function call ambiguous?

#include <iostream>
using namespace std;

iostream must be including algorithm and, since you decided to include the entire std namespace in your file, you have a collision with std::swap. Remove using namespace std;

EDIT: As @chris points out in the comments, std::swap was moved to <utility> in C++11.

Call of overloaded function is ambiguous... But Why? Template problem

As mentioned in the comment you should do some changes to remove the ambiguity between the std::swap and yours. remove using namespace std; and use std:: before cout:

#include <iostream>

template<typename T>
void swap(T &a, T &b)
{
T dummy = a;
a = b;
b = dummy;
}
template<typename T>
void swap(T a[], T b[], int size)
{
for(int i = 0; i < size;i++)
{
T dum = a[i];
a[i] = b[i];
b[i] = dum;
}
}
int main()
{
int a = 20;
int b = 10;
swap(a, b);
std::cout << "a: " << a << "\t" << "b: " << b << std::endl;

int eights[] = {8, 8, 8, 8, 8, 8, 8};
int threes[] = {3, 3, 3, 3, 3, 3, 3};
for(int i = 0; i <7;i++)
{
std::cout << eights[i] << "\t";

}
for(int i = 0; i <7;i++)
{
std::cout << threes[i] << "\t";

}

swap(eights, threes, 7);
for(int i = 0; i <7;i++)
{
std::cout << eights[i] << "\t";

}
for(int i = 0; i <7;i++)
{
std::cout << threes[i] << "\t";

}
}

Why name lookup can't find std::swap when a base class has a swap function in C++?

For unqualified name lookup:

name lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined.

So the name swap is examined in class A firstly, it's not found, then examined in class Parent, it's found, then name lookup stops. std::swap introduced into global scope won't be found at all.

And

Why the ADL here can't find the std::swap and use it ?

You're passing longs to swap, while ADL works with class types, but not fundamental types.

  1. For arguments of fundamental type, the associated set of namespaces and classes is empty

BTW: In this special case even you change to pass some class types defined in std namespace to swap ADL won't be considered either.

First, the argument-dependent lookup is not considered if the lookup set produced by usual unqualified lookup contains any of the following:

  1. a declaration of a class member

Parent::swap is a class member which is found by usual unqualified name lookup, ADL still won't be considered.

How do I make std::sort not have name collision between std::swap and my namespace's templated swap?

A workaround is to create a better overload:

// No modifiable code
namespace my
{
template<class T> void swap(T a, T b) { /*.. */ }
struct Obj { /*..*/ };
}

// Your code:
namespace my
{
void swap(Obj& lhs, Obj& rhs)
{
// my::swap<Obj&>(lhs, rhs);
std::swap(lhs, rhs);
}
}

// In namespace you want.
void doSortStuff()
{
std::vector<my::Obj> arr;
std::sort(arr.begin(), arr.end());
}

Then, between the 3 valid overloads, all are exact match, but the non-template is preferred.

Ambiguous call to overloaded function (learning about templates)

You are redefining the function swap with the same signature, so you're having an ambiguous definition of it, and, consequently, an ambiguous call.

If you want to maintain the function with the same signature, you should either choose to use not the "using namespace std;", which will not shadow your swap() definition, or simply define tthe function in another namespace.

Example:

namespace your_namespace {

template <typename X>
void swap(X &a, X &b) {
X temp = a;
a = b;
b = temp;
}

}

int foo(10), bar(20);
std::cout << "foo: " << foo << "; bar: " << bar << std::endl;

your_namespace::swap(foo, bar);
std::cout << "foo: " << foo << "; bar: " << bar << std::endl;

Output:

foo: 10; bar: 20
foo: 20; bar: 10

Regards!

Is there any coincidences I've done while templatizing this function in C++, using void swap()?

You should just use std::swap rather than your own.

But, for an explanation of your error:

using namesapce std;

Assuming that actually says namespace in your code, that is the problem. There is a swap in namespace std.

If you remove the using directive and qualify your std uses with std:: then you can call your swap unqualified live link

#include <iostream>
#include <string>

template <typename T>
void swap(T &a, T &b) {
T temp = a; //Temporary copy to reuse
// a = (b = temp); // incorrect
a = b;
b = temp;
}
int main() {
int x, y;
std::cin >> x >> y;
std::cout << "X: " << x << "\t Y: " << y << '\n';
swap(x, y);
}

As to why it happens to work with std::string: there is a overload of std::swap for strings that is a better match than your templated swap, so the compiler unambiguously picks that one

https://en.cppreference.com/w/cpp/string/basic_string/swap2



Related Topics



Leave a reply



Submit