ZWI #1: Jak wykryć kontenery asocjacyjne w czasie kompilacji

Tym postem rozpoczynam kolejną serię – ZWI (Zapytane w Internecie). W planach jest co najmniej jeden wpis ;​) Posty będą przedstawiały pytania, na które odpowiedziałem na różnej maści forach, które (lub których odpowiedzi) uznałem za godne uwagi.

Na pierwszy ogień idzie następujące pytanie z forum 4programmers:

Mam prostą funkcję

template <typename Container, typename Value>
bool contains(const Container& container, const Value& value)
{
    return std::find(std::begin(container), std::end(container), value)
        != std::end(container);
}

Dla kontenerów asocjacyjnych (set, multiset, unordered_set, map itd.) można wykorzystać metodę find(), która jest szybsza niż globalne find(). Pytanie czy da się w prosty i elegancki sposób wykryć taką sytuację, żeby wywołać container.find(), bo nie uśmiecha mi się pisać specjalizacji dla każdego typu kontenera.

Lawful Evil #1 – kwadraty magiczne

Rozpoczynam nową serię: Lawful Evil. Jest to znana kategoria postaci z DnD, charakteryzująca się działaniem zgodnym z obowiązującym porządkiem, jednak zaprzeczającym jego duchowi.

W moim wykonaniu jest to wykonywanie zadań (domowych czy innych) zgodnie z literą zadania, ale w sposób taki, aby było jasne, że to parodia/żart. Zadania będą maksymalnie przekombinowane, mogą zawierać celowo rażące błędy i, w ramach możliwości, ich stopień skomplikowania uczyni je niemożliwymi do wytłumaczenia nauczycielowi/wykładowcy.

Misja Gynvaela 003

MISJA 003            goo.gl/ZPQvV0               DIFFICULTY: ██░░░░░░░░ [2/10]

Tym razem nie trzeba nic robić. Wystarczy uruchomić poniższy skrypt, chwilkę
poczekać, a hasło zostanie wypisane. No, taką dłuższą chwilkę...

#!/usr/bin/python
def magic1(a, b):
  o = 0
  i = 0
  while i < a:
    o += 1
    i += 1
  i = 0
  while i < b:
    o += 1
    i += 1
  return o
def magic2(a, b):
  o = 0
  i = 0
  while i < b:
    o = magic1(o, a)
    i += 1
  return o
n1 = int("2867279575674690971609643216365"
         "4161626212087501848651843132337"
         "3373323997065608342")
n2 = int("1240905467219837578349182398365"
         "3459812983123659128386518235966"
         "4109783723654812937")
n = magic2(magic1(n1, n2), 1337)
print hex(n)[2:-1].decode("hex").splitlines()[0]

Misja Gynvaela 002

MISJA 002                                        DIFFICULTY: ███░░░░░░░ [3/10]

Przechwyciliśmy fragment komunikacji pomiędzy dwoma podejrzanymi. Sądzimy, że
to hasło administratora do jednego z systemów, na których mogą znajdować się
kluczowe dla sprawy dane.

                 ╭┈┈                                     ┈┈╮  
                 ┊ QW== QT== QT== QQ== QU== Qd== QU== Qd== ┊
                   QX== QV== QW== Qe== QT== QR== QU== QT==
                   QT== QU== QX== QU== QT== QR== QT== QQ==
                 ┊ QW== Qe==               »goo.gl/4Iuxdi« ┊ 
                 ╰┈┈                                     ┈┈╯   

Niestety, pomimo, iż wiemy, że użyte zostało kodowanie Base64, nie jesteśmy w
stanie zdekodować ukrytej wiadomości. Nasi technicy uparcie twierdzą, że po
zdekodowaniu wychodzi „AAAAAAAAAAAAAAAAAAAAAAAAAA”, ale sądzimy, że nie mają
racji.

Zwracamy się więc do Ciebie z prośbą o pomoc - zrzuć okiem na powyższą
wiadomość i sprawdź czy nie ma czasem drugiego dna.

Jak przeładowywać operatory w mojej klasie?

Kiedy i które operatory przeładowywać?

Dość przewrotnie odpowiem: kiedy zajdzie taka potrzeba. Podstawą jest zachowanie logiki kodu (Samochod + Samochod nie ma zbyt sensu, ale Currency + Currency już tak) oraz konwencji języka (lub frameworka), np. w przypadku operatora <<.

Wyjście i wejście ze strumienia, czyli operatory << i >>

Tutaj nie ma wielkiej filozofii. Dobrze by było osiągnąć pełną serializację, t.j. zagwarantować poprawność kodu z listingu poniżej, ale w praktyce jest to więcej roboty niż to warte dla większości klas. Szczególnie, że nawet biblioteka standardowa nie zachowuje się w ten sposób, np. dla klasy std::string.