Namespaces and friend functions

Started by
5 comments, last by Kylotan 22 years, 8 months ago
Ok, given that I make a lot of data types that I want to use in STL containers, it makes sense for me to write a specialisation of the std::swap function. std::swap gets used a lot when sorting or reordering containers. The default std::swap looks something like this:
void swap(T& t1, T& t2)
{
    T temp(t2);
    t1 = t2;
    t2 = temp;
} 
This is adequate for most needs, but quite often you have a class which contains mostly pointers to data. Therefore you can write a much more efficient version of std::swap for your own types just by swapping pointers rather than using whole assignments which involve copying all the data that is pointed to. (Assuming you wrote a decent operator= function. This is an example of where doing 1 thing the right way actually makes things harder for you in others!) Now, most such specialised swap functions will need access to private or protected data members. This means they need to be a friend function. Also, the swap function is meant to be a specialisation of std::swap, therefore it should be in the std namespace. Otherwise the default version could be called when I actually wanted my specialised version. The problem is, I can''t quite work out how to do this properly. If I use this code: // in MyClass header friend void swap(MyClass& x, MyClass& y); // in MyClass cpp namespace std { void swap(MyClass& x, MyClass& y) { ...etc... I get the error "cannot access private member." Because the friend function is referring to swap, and the function I made is actually std::swap. If I change the line in the header file to: friend void std::swap(MyClass& x, MyClass& y); I get the error "''std'' : is not a class or namespace name". If I change the line in the header file to: namespace std { friend void swap(String& x, String& y); } I get this error: "syntax error : ''namespace''". So. What is the answer? I need my function in std:: and I need it to have access to private members to work properly.
Advertisement
What a good question. In you cpp file where you define swap
can you just do void std::swap(... ?
No. If I do that, then it says that ''swap is not a member of std''. If I then #include something like <algorithm> to convince it of this fact, it says "''swap'' : unable to resolve function overload". And that''s without even getting as far as deciding whether it can access private members or not.
As it happens, I got around my own problem by defining a public member function called swap, and had the std::swap call that one. This seems to be what is needed. But it doesn''t solve the original problem as such (if it is even solvable), being the friend/namespace conflict.
If you want a specialization of swap, I think you are doing it the wrong way.


    // In  Header.h - Class header#pragma once#include <algorithm>class C{        // THIS DOES NOT COMPILE WITH VC++ 6	template <class T> friend void std::swap(T &, T &);public:	C()	{}	~C()	{}private:	void	F()  {};};namespace	std{	template <>	void	swap<C>( C &c, C &d )	{		c.F();   // call private function	}}    


Provide a full specialization of std::swap. This doesn't not compile with VC++ 6 because there are some problems with friend templates with VC, but I think the syntax should be correct

I'm at work now and have no access to other compilers, I will check later when I get home.



Edited by - void on July 29, 2001 11:57:19 PM
Keep in mind the reason that swap works the way it does is to remain exception-safe. At no point during the swap should any objects be in an inconsistant state should an exception occur. I don''t know what your particular efficiency improvement is, but just take care that it doesn''t compromise safety. Once you start down the dark path, forever will it dominate your destiny.
Checked it with g++ 2.95. It compiles fine.

However, I should also let you know it is generally not advisable to add things to the std namespace. But if you got a good reason, go ahead.

This topic is closed to new replies.

Advertisement