Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
192 views
in Technique[技术] by (71.8m points)

c++ - Why do the usual access control checking applies to names used to specify explicit instantiation when accessed through template parameters?

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 speci?cations) 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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...