αλεχολυτ
αλεχολυτ

Reputation: 5039

Restrict template friends of a class

Consider the following code:

#include <iostream>

class S {
    static const int i = 42;
    template <class T>
    friend void f();
};

template <class T>
void f()
{
    std::cout << S::i << "\n";
}

int main() 
{
    f<int>();
    f<double>();
}

All I want here is to allow access to private part of a class S to f<int>, but not for f<double>. I.e. I want to get compiler error like 'i' is a private member of 'S' for f<double>() line.

How to achive this?

Upvotes: 4

Views: 93

Answers (2)

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385274

The template instantiation is a function, so just name it: void f<int>().

You need a prior declaration, though:

[C++03: 11.4/9 | C++11/C++14: 11.3/11]: If a friend declaration appears in a local class (9.8) and the name specified is an unqualified name, a prior declaration is looked up without considering scopes that are outside the innermost enclosing non-class scope. For a friend function declaration, if there is no prior declaration, the program is ill-formed. [..]

(This wasn't the case for the friend-inside-template-declaration that you had originally, because templates are looked up a little later in the parsing process.)

Here's the finished solution:

#include <iostream>

template <class T>
void f();

class S {
    static const int i = 42;
    friend void f<int>();
};

template <class T>
void f()
{
    std::cout << S::i << "\n";
}

int main() 
{
    f<int>();
    f<double>();
}

Now the only error is caused by the f<double>() call.

(live demo)

Upvotes: 8

Tristan Brindle
Tristan Brindle

Reputation: 16834

You need to declare (or just define) the template function before the class S. Then you can just say that you want it to be friends with f<int>(). Like so:

template <class T> void f();

class S {
    static const int i = 42;
    friend void f<int>();
};

template <class T>
void f()
{
    std::cout << S::i << "\n";
}

Upvotes: 2

Related Questions