blog.michalt.pl

Kilka słów o modułach w C++20, ale niestety tylko teoretycznie

08.05.2019 22:58 - Tech

W najbliższym czasie zamierzam skrobnąć kilka wpisów poświęconych tematyce języka C++. Dziś chciałbym poruszyć temat modułów które miały znaleźć się już w standardzie 17. Chciałbym uprzedzić, że nie jestem pewien co do tego czy przedstawione tu fragmenty kodu będą zgodne z finalną wersją standardu. Dlaczego tylko teoretycznie? Ponieważ to jedna z bardzo istotnych nowości którą niestety nie udało mi się przetestować z powodu braku wsparcia kompilatorów.

Przejdźmy do konkretów. Nowe rozwiązanie ma na celu między innymi rozwiązanie problemu wpływania na siebie kodu między nagłówkami. Moduły w przeciwieństwie do nagłówków będą bardziej hermetyczne. W teorii mają one być również rozwiązaniem bardziej optymalnym w procesie kompilacji – kompilator nie będzie zaglądał do pliku modułu wielokrotnie tak jak to miało miejsce w przypadku nagłówków. Co istotne, nagłówki będzie można używać nadal obok modułów.


Spróbujmy zatem pobawić się w teoretyków i stworzyć nasz moduł w C++:

plik cat.cpp:

module;
#include <iostream>
export module Cat;
export class Cat {
public:
  void meow() {
    std::cout << "meow! meow! meow!";
  }
};

class Dog {
public:
  void bark() {
    std::cout << "Wooff! Wooff! Wooff!";
  }
};

export int getMeowString(int meowTimes) {
  std::string meow = "";
  while(meow-- > 0)
    meow += "meow! ";
  return meow;
}

W pierwszej linijce naszego kodu informujemy kompilator o tym, że ma do czynienia z modułem, w trzeciej zaś definiujemy jego nazwę – czyli w tym przypadku „Cat”. Powinniśmy jednak zwrócić uwagę na pewien istotny fakt. Część jego zawartości nie musi być dostępna na zewnątrz. Zwróć uwagę na słówko export w czwartej i szesnastej linijce kodu. W pierwszym przypadku wyeksportowana zostaje cała klasa z jej zasobami, w drugim zaś funkcja getMeowString(). Jak zapewne się domyślasz, w kodzie korzystającym z tego modułu nie będzie można skorzystać z klasy Dog, ale sama klasa Cat może korzystać z obiektów jej instancji lub innych zasobów które nie zostałyby wyeksportowane.

Jak zaimportować moduł? Bardzo prosto:

plik main.cpp

import Cat;
#include <iostream>
int main() {
  Cat cat;
  cat.meow();
  std::cout << makeMeowString(5); 
}

Tu nie trzeba tak naprawdę wiele tłumaczyć. Za import odpowiedzialna jest pierwsza linijka kodu. W dalszych, wewnątrz funkcji main korzystamy z udostępnionych zasobów.


Warto wspomnieć o tym, że kompilatory Clang i GCC częściowo już obsługują standard 20 i w niedalekiej przyszłości może również pojawić się obsługa modułów. Teoretycznie we wcześniej wspomnianym wariancie kompilatora GCC istnieje możliwość włączenia ich obsługi poprzez dodanie argumentu -fmodules-ts. Podobnie sprawy się mają w przypadku Clanga który wymaga podania argumentu -fmodules. Ponadto tryb kompilacji eksperymentalnie wspieranego standardu, w obu kompilatorach można włączyć dodając flagę -std=c++2a.


Czuję spory niedosyt ponieważ nie udało mi się skompilować kodu z modułami. Z pewnością wrócę jeszcze do tego tematu i w niedalekiej przyszłości opiszę kilka innych nowości ze standardu 20.