2012-03-28 4 views
13

В нашей печально известной лампочке есть интересная статья о how to circumvent the access check.Может ли указатель на участников обходить уровень доступа члена?

Это полностью подтверждается этим простым кодом:

#include <iostream> 

template<typename Tag, typename Tag::type M> 
struct Rob { 
    friend typename Tag::type get(Tag) { 
    return M; 
    } 
}; 

// use 
struct A { 
    A(int a):a(a) { } 
private: 
    int a; 
}; 

// tag used to access A::a 
struct A_f { 
    typedef int A::*type; 
    friend type get(A_f); 
}; 

template struct Rob<A_f, &A::a>; 

int main() { 
    A a(42); 
    std::cout << "proof: " << a.*get(A_f()) << std::endl; 
} 

Который компилирует и работает (выходные 42) с gcc 4.3.4, gcc 4.5.1, GCC 4.7.0 (см комментарий user1131467), и компилирует с Clang 3.0 и C Comeau/C++ 4.3.10.1 в C++ 03 строгого режима и MSVC 2005.

спросил меня Luchian на this answer, в котором я использовал его, чтобы оправдать, что это было на самом деле законно. Я согласен с Лучианом в том, что это странно, но как Clang, так и Comeau являются близкими соперниками для большинства доступных «стандартных» компиляторов (гораздо больше, чем MSVC по умолчанию) ...

И я ничего не мог найти в черновиках Стандартов, которые я имею в наличии (n3337 - последняя версия, в которой я получил свои руки).

Итак ... может ли кто-либо на самом деле оправдывать то, что это законно или нет?

+0

FYI Это выводит 'proof: 42' с' g ++ - 4.7 (Debian 4.7.0-1) 4.7.0' в обоих '-std = C++ 11' и' -std = gnu ++ 11' –

+0

Извините, это мое плохое. Это компилируется, то, что не компилировалось, было http://stackoverflow.com/a/6886432/673730 - и я пытался получить доступ к частной функции, а не к элементу данных. –

+0

Btw Я все еще ищу ответ на этот вопрос, если бы ответ сработал, это было именно то, что я искал, но это не так. –

ответ

13

Да, это законно. Соответствующий текст на §14.7.2/12, говоря о явном шаблоне конкретизации:

12 Обычного доступа проверка правила не применяется к именам, используемых для определения явной инстанциации. [Примечание: В частности, аргументы шаблона и имена, используемые в деклараторе функций (включая типы параметров, типы возвращаемых данных и спецификации исключений), могут быть частными типами или объектами, которые обычно не будут доступны, и шаблон может быть шаблоном-членом или функция члена, которая обычно не была бы доступной. - примечание к концу]

Emhpasis mine.

+4

Ах! Это, вероятно, то, что мне больше всего нравится в Стандарте, чтобы иметь всестороннее представление о чем-то, вам просто нужно протащить все это и собрать кусочки вместе. –

+1

@ MatthieuM .: Но это также почему я ненавижу стандарт! :) EDIT: Whoosh! – GManNickG

+0

Это должно было быть ироничным;) Хотя теперь, когда он находится на github, возможно, мы могли бы предложить отредактировать, чтобы сшивать этот абзац из приведенного Джеймса! –

5

Код явно незаконный (и требуется диагностика времени компиляции). В строке:

template struct Rob<A_f, &A::a>; 

выражение A::a доступ к закрытому члену в A.

Стандарт очень ясно говорит об этом: Контроль доступа “ применяется равномерно все имена, будь то имена упоминаются из деклараций или выражений. “ (§11/4, добавлено выделение). Поскольку a является частным именем в A, любая ссылка на него за пределами A является незаконной.

+3

Это фактически не является незаконным, исключение добавляется позже для явных шаблонных экземпляров. «Все», очевидно, вводят в заблуждение, это «все, если не указано иное». Я не буду ниспровергать, потому что это совершенно неинтуитивно. – GManNickG

+0

@GManNickG На самом деле, это не ясно, и я думаю, что DR в порядке. В стандарте «все» означает «все», а не «все, если не указано иное», и контекст в §14.7.2 может допускать другие интерпретации (хотя они не очень естественны). Это выглядит как противоречие, а это значит, что a DR в порядке. –

+0

Вы правы, нет никакой необходимости, чтобы эта квалификация была там. – GManNickG