Question

Is there any way to specialize a function (say, std::swap) for a private class?

For example, when I test this:

#include <algorithm>

class Outer
{
    struct Inner
    {
        int a;
        void swap(Inner &other)
        {
            using std::swap;
            swap(this->a, other.a);
        }
    };
public:
    static void test();
};

namespace std
{
    template<> void swap<Outer::Inner>(Outer::Inner &a, Outer::Inner &b)
    { a.swap(b); }
}
void Outer::test()
{
    using std::swap;
    Inner a, b;
    swap(a, b);
}
int main()
{
    Outer::test();
    return 0;
}

I get this:

Test.cpp:20:47: error: 'Inner' is a private member of 'Outer'
    template<> void swap<Outer::Inner>(Outer::Inner &a, Outer::Inner &b)
                                              ^
Test.cpp:5:12: note: implicitly declared private here
    struct Inner
           ^
Test.cpp:20:64: error: 'Inner' is a private member of 'Outer'
    template<> void swap<Outer::Inner>(Outer::Inner &a, Outer::Inner &b)
                                                               ^
Test.cpp:5:12: note: implicitly declared private here
    struct Inner
           ^
Test.cpp:20:33: error: 'Inner' is a private member of 'Outer'
    template<> void swap<Outer::Inner>(Outer::Inner &a, Outer::Inner &b)
                                ^
Test.cpp:5:12: note: implicitly declared private here
    struct Inner

(I do realize declaring a friend swap that can be found through ADL avoids this issue for swap, but that's irrelevant to my question. swap is just an example.)

Was it helpful?

Solution

You could add a friend declaration of the std::swap<Inner>(Inner&, Inner&) inside Outer

#include <algorithm>

class Outer
{
    struct Inner
    {
        int a;
        void swap(Inner &other)
        {
            using std::swap;
            swap(this->a, other.a);
        }
    };

    friend void std::swap<Inner>(Inner&, Inner&) noexcept;
public:
    static void test();
};

namespace std
{
    template<> void swap<Outer::Inner>(Outer::Inner &a, Outer::Inner &b) noexcept
    { a.swap(b); }
}

void Outer::test()
{
    using std::swap;
    Inner a, b;
    swap(a, b);
}

int main()
{
    Outer::test();
    return 0;
}

Live Example

OTHER TIPS

Don't extend the std namespace.

If you want to create a swap function for Inner, make it a private function in Outer

#include <algorithm>

class Outer
{
    struct Inner
    {
        int a;
        void swap(Inner &other)
        {
            std::swap(this->a, other.a);
        }
    };

    static void swap(Inner& a, Inner& b);

public:
    static void test();
};

void Outer::test()
{
    Inner a, b;
    swap(a, b);
}

void Outer::swap(Inner& a, Inner& b)
{
    a.swap(b);
}

int main()
{
    Outer::test();
    return 0;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top