Я бы рекомендовал использовать брелки. Используя Keychain, вы можете сохранить свой пароль в зашифрованном виде. Взгляните на образец Apple GenericKeychain .
NSUserDefaults немного менее безопасен по сравнению с Keychain. В NSUserDefaults данные могут легко получить доступ, если известен конкретный ключ. Это не относится к Keychain.
Вы также можете преобразовать NSUserDefaults в Keychains. Посмотрите здесь .
В моем суматошном мнении и на основе §13.3.3 / 1 Наилучшая жизнеспособная функция [over.match.best] , оператор перегруженного преобразования без шаблона (т. е. operator int() const
) имеет более высокий приоритет в отношении выбора разрешения перегрузки, чем его шаблонный аналог (т. е. template <typename T> operator T () const
).
Таким образом, перегруженное разрешение правильно выбрало бы operator int() const
по сравнению с template <typename T> operator T () const
, поскольку является наилучшей жизнеспособной функцией.
Кроме того, поскольку версия без шаблона будет выбрана над шаблоном (т. е. шаблон не будет материализован / квалифицирован компилятором), class Var
будет иметь одну функцию преобразования, и, следовательно, требование в §6.4.2 / 2 Оператор switch [stmt.switch] для единственного интегрального преобразования будет выполнен.
Следовательно, Clang прав, а GCC ошибочен.
Вот соответствующие цитаты, но окончательный ответ во многом зависит от интерпретации.
N3797 6.4.2 / 2:
Условие должно быть цельного типа, типа перечисления или типа класса , Если тип класса, условие контекстно неявно преобразуется (раздел 4) в интегральный или перечисляемый тип.
blockquote>4/5:
Определенные языковые конструкции требуют преобразования в значение, имеющее один из определенного набора типов, соответствующих конструкции. Выражение
blockquote>e
типа классаE
, появляющееся в таком контексте, называется , контекстно неявно преобразованным в заданным типомT
и хорошо сформированным тогда и только тогда, когдаe
может неявно преобразуется в типT
, который определяется следующим образом:E
выполняется поиск функций преобразования, возвращаемым типом которых является cvT
или ссылка на cvT
, чтоT
разрешено контекстом. Должен быть ровно один такойT
.14.5.2 / 6:
Специализация функции преобразования не найдена при поиске по имени. Вместо этого рассматриваются все шаблоны функций преобразования, видимые в контексте использования. Для каждого такого оператора, если вывод аргумента преуспевает (14.8.2.3), полученная специализация используется, как если бы она была найдена путем поиска по имени.
blockquote>14.5.2 / 8:
Разрешение перегрузки (13.3.3.2) и частичное упорядочение (14.5.6.2) используются для выбора наилучшей функции преобразования между несколькими специализациями шаблонов функций преобразования и / или функциями преобразования без шаблона.
blockquote >Интерпретация 1: 4/5 гласит «функции преобразования», а не «функции преобразования и шаблоны функций преобразования». Поэтому
Var::operator int() const
является единственным вариантом, а clang является правильным.Интерпретация 2 [слабый?]: 14.5.2 требует от нас сравнить шаблон функции преобразования путем разрешения перегрузки и частичного упорядочения на том же начальном как функция преобразования без шаблона. Они сравнивают специализированные функции и функции шаблонов, а не шаблоны функций, поэтому мы будем делать вывод аргумента шаблона. Вычисление аргумента шаблона для шаблона функции преобразования требует целевого типа. Хотя у нас обычно есть более четкий тип цели, в этом случае мы просто попробуем (теоретически все) все типы в наборе допустимых типов. Но ясно, что функция без шаблона является лучшей жизнеспособной функцией, которая включает все специализированные шаблоны, поэтому разрешение перегрузки выбирает функцию без шаблона. clang является правильным.
Интерпретация 3: Поскольку для разрешения перегрузки требуется вычет аргумента шаблона, а вывод аргумента шаблона требует известного целевого типа, сначала следует рассмотреть семантику 4/5, а затем ее преобразованный тип (если любой) может использоваться для процесса разрешения перегрузки. 14.5.2 требует рассмотрения шаблона функции преобразования, но затем мы обнаруживаем, что существует несколько допустимых типов
T
, для которых у нас есть функция преобразованияT
[эта функция, возможно, является специализированной функцией). Программа плохо сформирована, поэтому g ++ корректна.
Если я правильно читаю этот раздел при перегрузке, Clang корректен
13.3.3 Наилучшая жизнеспособная функция [over.match.best]
[.. .] Учитывая эти определения, жизнеспособная функция F1 определяется как лучшая функция, чем другая жизнеспособная функция F2, если для всех аргументов i ICSi (F1) не является хуже конверсионной последовательностью, чем ICSi (F2), а затем [... ]
- F1 - это функция без шаблона, а F2 - специализированная функция шаблона или, если не это, [...]
blockquote>Черновик свободен читать. Не уверены, были ли внесены изменения в 13.3.3 в окончательную спецификацию (я не заплатил за нее)
http://www.open-std.org/jtc1/sc22/ wg21 / docs / papers / 2012 / n3337.pdf
Я бы установил ошибку G ++ :-) Они могут вернуться с другим разделом стандарта, чтобы оправдать, но, похоже, совместимы с нестандартными.
Редактировать комментарий пользователя:
Предположим, что f является перегруженным именем функции. Когда вы вызываете перегруженную функцию f (), компилятор создает набор функций-кандидатов. Этот набор функций включает в себя все функции с именем f, к которым можно получить доступ из точки, где вы вызвали f (). Компилятор может включать в качестве функции-кандидата альтернативное представление одной из этих доступных функций с именем f для облегчения разрешения перегрузки.
После создания набора функций-кандидатов компилятор создает набор жизнеспособных функций. Этот набор функций является подмножеством функций-кандидатов. Количество параметров каждой жизнеспособной функции согласуется с количеством аргументов, которые вы использовали для вызова f ().
blockquote>
6.4.2 / 2 Оператор switch
(выделение)
Условие должно быть целочисленного типа, типа перечисления или типа класса, для которого один неявный существует функция преобразования в интегральный или перечисляемый тип (12.3). Если условие имеет тип класса, условие преобразуется путем вызова этой функции преобразования, а результат преобразования используется вместо исходного условия для остальной части этого раздела.
blockquote>Поэтому моя интерпретация заключается в том, что g ++ здесь верен.
T
не может быть выведена как какой-либо целочисленный или перечисляемый тип, и в этом случае только одна функция преобразования, которая квалифицируется.
– hvd
30 July 2014 в 22:53
int x = v; char c = v; ...
. Тот факт, что тип не может быть выведен, не делает его не преобразованием. Обратите внимание, что цитата не говорит в контексте оператора switch
или чего-то подобного, она касается только ее существования.
– David Rodríguez - dribeas
30 July 2014 в 23:18
Я считаю, что gcc корректен, но стандарт ошибочен.
gcc корректен, потому что стандарт задает один неявный оператор преобразования для целых или перечисляемых типов для типов, используемых в switch
.
Стандарт неверен, поскольку обнаружение этого случая связано с решением проблемы остановки.
operator T
может иметь приложенное к нему предложение SFINAE произвольной сложности. Компилятор под стандартом должен определить, есть ли T
, чтобы T
был enum
.
template<class...Ts>
struct evil {
enum { bob = 3+sizeof...(Ts) };
};
struct test {
operator int() const { return -1; };
template<class T, typename std::enable_if<T::bob==2>::type* unused=nullptr>
operator T() const { return T::bob; }
};
int main() {
switch( test{} ) {
case -1: std::cout << "int\n"; break;
case 2: std::cout << "bob\n"; break;
default: std::cout << "unexpected\n"; break;
}
}
Вышеприведенный код демонстрирует случай, когда мы имеем бесконечное число из enum
s неявно доступны. У нас есть operator T
, который будет отличать тип T
тогда и только тогда, когда T::bob==2
. Теперь в нашей программе нет таких enum
s (и даже если бы мы удалили 3+
, все равно этого не было бы, потому что это не enum class
- легко исправлено).
Таким образом, test
может быть преобразован только в int
, и поэтому инструкция switch
должна компилироваться. gcc отказывает в этом тесте и утверждает, что template operator T
делает его неоднозначным (не сообщая нам, что T
, естественно).
Замена enum type
на enum class type
, и удаление 3+
делает switch
заявление не соответствует стандарту. Но для компилятора, чтобы понять это, он в основном должен создать все возможные шаблоны в программе, которые ищут секрет enum
с соответствующим свойством. С небольшой работой я могу заставить компилятор решить NP полные проблемы (или, исключая ограничения компилятора, проблему остановки), чтобы определить, следует ли компилировать прогрму или нет.
Я не знать правильную формулировку. Но формулировка, как написано, не звучит.
operator T()
может иметь предложение SFINAE, и все еще можно использовать?
– aschepler
31 July 2014 в 01:29
template<class T,class=std::enable_if_t<T::bob==2>> operator T()
– Yakk - Adam Nevraumont
31 July 2014 в 01:44
operator long<long,void>()
может испортить мой план: он существует, и SFINAE не может блокировать его существование. Таким образом, это может только занять его уродливую голову, когда приходят идеи lite. Хм.
– Yakk - Adam Nevraumont
31 July 2014 в 01:52
operator long<long, void>()
? Что существуют шаблонные аргументы, чтобы замена была успешной? Как насчет template<class T, std::enable_if_t<T::bob==2>* = nullptr> operator T()
?
– dyp
31 July 2014 в 20:52