Search code examples
c++privatefriendtemplate-specializationspecialization

Specializing a function for a private class?


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.)


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