ZWI #2 – zaprzyjaźniona pojedyńcza specjalizacja szablonu

Do napisania tej notki zainspirowało mnie to pytanie na forum. Lekko parafrazując podany kod, szablon klasy wyglądał następująco:

template<typename T>
void bar(Foo<T> f)
{
    DBG(f.val);
}
 
template<typename T>
struct Foo
{
    Foo(T val) : val{val} {}
 
    template<typename U>
    friend void bar(Foo<U>);
 
private:
    T val;
};

Powyższy kod niepotrzebnie1 zaprzyjaźnia wszystkie specjalizacje bar. Na przykład, dla Foo<int>, zaprzyjaźniona zostanie zarówno bar<int>, jak i każda inna specjalizacja, chociażby bar<float>. W efekcie legalna będzie również taka specjalizacja:

template<>
void bar<int>(Foo<int> x)
{
    Foo<float> y{static_cast<float>(x.val)};
    DBG(y.val);
}

W zdecydowanej większości przypadków nie ma to sensu, a zamierzeniem jest zaprzyjaźnienie wyłącznie specjalizacji po tym samym typie, po którym konkretyzowana jest klasa. W takim wypadku można zaprzyjaźnić konkretną specjalizację:

template<typename T>
struct Foo
{
    // ...
    friend void bar<T>(Foo<T>);
    // ...
};

Lub, krócej, wykorzystując dedukcję typów i injected class name:

template<typename T>
struct Foo
{
    // ...
    friend void bar<>(Foo);
    // ...
};

1Zakładając, że autor chciał zaprzyjaźnić wyłącznie bar<T>, ale nie wiedział jak. Tak było w przypadku wspomnianego wątku.

3 thoughts on “ZWI #2 – zaprzyjaźniona pojedyńcza specjalizacja szablonu

Leave a Reply

Your email address will not be published.