4

The C++11/14 standards state the following in note 14.7.2/12 [temp.explicit]:

The usual access checking rules do not apply to names used to specify explicit instantiations. [ Note: In particular, the template arguments and names used in the function declarator (including parameter types, return types and exception specifications) may be private types or objects which would normally not be accessible and the template may be a member template or member function which would not normally be accessible. — end note ]

I would expect to be allowed to use a template if I can instantiate it.

I tried with gcc-4.8.2 and I get the expected behaviour when I access private members of explicitly named classes. However, the access checking rules do apply when I access private members through template parameters. Is this a bug in gcc, or am I missing something?

In the code below, the only difference between 'succeeds' and 'fails' is that the former accesses the private member directly via 'A', while the latter accesses it via the template parameter 'T'. The compiler complains that privateFoobar is private in that context.

#include <iostream>
#include <string>

struct A
{
private:
    std::string privateFoobar() {return "private foobar!";}
};

typedef std::string (A::*Foobar)();

template <class Type, Type value>
struct Access
{
    static Type getValue() {return value;}
};

template <class T>
struct IndirectAccess
{
    static Foobar succeeds() {return Access<Foobar, &A::privateFoobar>::getValue();}
    static Foobar fails() {return Access<Foobar, &T::privateFoobar>::getValue();}
};

template class Access<Foobar, &A::privateFoobar>;

int main() {
    std::cout << (A().*Access<Foobar,&A::privateFoobar>::getValue())() << std::endl;
    std::cout << (A().*IndirectAccess<A>::succeeds())() << std::endl;
    std::cout << (A().*IndirectAccess<A>::fails())() << std::endl;
}

In case you are wondering what is the use case for such a sackable offence: creating a framework that would automate the configuration of an application based on implementation choices for the selected components.

M.M
  • 138,810
  • 21
  • 208
  • 365
Come Raczy
  • 1,590
  • 17
  • 26
  • The standard quote you cite is about explicit instantiation; the program you present contains no explicit instantiations. I submit the the issue is that you are unclear on what an explicit instantiation is. Take a look at 14.7.2/1 through /4. – Casey May 28 '14 at 21:07
  • @Casey good point, I added the (pointless in this case) explicit instantiation and clarified my expectations. The question is more in line with: why would the standard enable me to explicitly instantiate a template if I am not able to use that instance in the code? what am I missing? – Come Raczy May 28 '14 at 21:39

1 Answers1

8

Explicit instantiations have to be at namespace scope, which means private members of classes would not normally be accessible. Without the rule you quote, this would be impossible:

class Foo
{
private:
  struct Bar;

  template<typename T> class Baz { };

public:
  void f();  // does things with Baz<Bar>
};

// explicit instantiation declaration
extern template class Foo::Baz<Foo::Bar>;

Without that rule, I would not be able to name Foo::Bar or even Foo::Baz at namespace scope, because those names are private to Foo.

Since I'm not actually using Foo::Bar or Foo::Baz here, just referring to their names to tell the compiler I'm instantiating the template somewhere else, there is no real access violation (although it is possible to use this rule to perform a very sneaky trick not possible otherwise).

Similarly, when I write the explicit instantiation definition in some other file, I need to be able to refer to the private names again at namespace scope.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • +1 but why not link to Johannes' exposition of his trick here on SO, instead of Dave Abrahams' rewrite. of course would need to find it first. – Cheers and hth. - Alf May 28 '14 at 22:14
  • Because I didn't know it was on SO, and Google returned the gist. It has the URL for Johannes' blog in the gist, so linking to that you get the original and the explanation. – Jonathan Wakely May 28 '14 at 22:18
  • 2
    I think [this](http://stackoverflow.com/a/1044437/464581) was Johannes' first exposition of it on SO. There he also exemplifies the counter-intuitive type system hole in member function pointer conversion rules. – Cheers and hth. - Alf May 28 '14 at 22:21