ã¢ãã³ç¬¬14ç« ïŒãC++20ãã¢ãžã¥ãŒã«ïŒModulesïŒå®å
šç§»è¡ã¬ã€ã
#include ãããå°çã»ãã¯ãæ±æããã®è±åŽãšè¶
é«éãã«ã
1970幎代ã®Cèšèªèªç以æ¥ãC/C++ããã°ã©ãã¯åäžçŽè¿ãã«ããã `#include` ããªããã»ããµãšãããåãªãããã¹ãã³ãããã®ä»çµã¿ã«äŸåãç¶ããŠããŸããããã®çµæãããããã¡ã€ã«ã®äºéèªã¿èŸŒã¿ãé²ãã€ã³ã¯ã«ãŒãã¬ãŒããã³ã³ãã€ã«é åºã«ããæåã®æ¿å€ãWindows.h ããµãŒãããŒãã£è£œã©ã€ãã©ãªãåæã«å®çŸ©ããå¶æªãªãã¯ãæ±æïŒ`#define min` / `max` ãªã©ïŒããããŠ1è¡ã®å€æŽã§æ°åååŸ
ãããã巚倧ãã«ãæéãšãã£ãæ°ã
ã®èŠçãå³ãã£ãŠããŸãããC++20 ã§å°å
¥ããããã¢ãžã¥ãŒã«ïŒModulesïŒãã¯ãããããã¹ãŠã®åé¡ãæ ¹æ¬è§£æ±ºãããC++å²äžæå€§ã®é©åœã§ããæ¬ç« ã§ã¯ã`export module` ãš `import` ã«ããã¯ãªãŒã³ãªã¢ãžã¥ãŒã«å¢çèšèšããã¯ãã®å®å
šéé¢ããããŠãã€ããªäžé衚çŸïŒBMIïŒã«ããè¶
é«éãã«ãã®ä»çµã¿ã培åºè§£èª¬ããææ°äžä»£ã®C++ã¢ãŒããã¯ãã£ã宿ãããŸãã
M8.1 ãªãC++ã¯åäžçŽãããããšãã¯ãã«èŠãããããŠããã®ãïŒ
ã#include ã¯åãªãããã¹ãã®ã³ããã§ããããšããæ ¹æ¬çæ¬ é¥ããããã«çŸä»£ã®å€§èŠæš¡éçºãç Žå£ããŠããã®ããè§£åããŸãã
ð§ ãã³ã®ã³å
茩
ãã³å
çâŠâŠïŒãããžã§ã¯ãã倧ãããªãã«ã€ããŠããã«ãæéãã©ãã©ãé·ããªããä»ã1åã®ãã«ãã«ãã«15åãããã£ãŠããŸãïŒããã `<windows.h>` ãã€ã³ã¯ã«ãŒããããã`std::min` ã `std::max` ããã¯ãã«ç Žå£ãããŠæå³äžæãªã³ã³ãã€ã«ãšã©ãŒãäœååãçºçããŸããâŠâŠïŒ
ð»ââïž ã·ãã¯ãå
ç
ã¬ããïŒãããããå
šC++ããã°ã©ãã50幎éåªãç¶ããŠããã#include ãããå°çããšããã¯ãæ±æïŒMacro LeakageïŒãããïŒ`#include` ãšããæ©èœã¯ã50幎åã«äœããããæå®ããããã¡ã€ã«ã®å
容ããã®å Žã«æååãšããŠãã¿è²Œããããã ãã®ç²éãªããªããã»ããµåœä»€ã«éããã®ããã
ð§ ãã³ã®ã³å
茩
ãã£ïŒïŒãã¿è²Œããªãã§ããïŒïŒãšããããšã¯ã100åã® .cpp ãã¡ã€ã«ãåã `<vector>` ãã€ã³ã¯ã«ãŒãããŠãããâŠâŠïŒ
ð»ââïž ã·ãã¯ãå
ç
ãã®éãããïŒäœäžè¡ãããããããã¡ã€ã«ã100åããŒãããããŒã¹ã»æ§æè§£æããããããã§ã¯ãã«ããçµãããªãã®ãåœç¶ããããã®50幎ã®åªããå®å
šã«æã¡åãããã«èªçããã®ããC++20 ã®ãã¢ãžã¥ãŒã«ïŒModulesïŒããªã®ããïŒ
ð MathEngine.ixx
// C++20 ã¢ãžã¥ãŒã«ã€ã³ã¿ãŒãã§ãŒã¹åäœ
export module MathEngine;
// å€éšã«å
¬éãããã·ã³ãã«ã« 'export' ãä»äž
export struct Vector2D {
float x;
float y;
Vector2D operator+(const Vector2D& other) const noexcept {
return { x + other.x, y + other.y };
}
};
export Vector2D makeVector(float x, float y) noexcept {
return { x, y };
}
// â ïž export ãã€ããªã颿°ã¯ãã¢ãžã¥ãŒã«å
éšå°çšããšãªãã
// å€éšãã絶察ã«åŒã³åºããªãïŒçã®ã«ãã»ã«åïŒïŒ
float internalDistanceSquared(const Vector2D& v) noexcept {
return v.x * v.x + v.y * v.y;
}
ð MainApplication.cpp
// ã¡ã€ã³ã¢ããªã±ãŒã·ã§ã³
import MathEngine;
import <iostream>;
int main() {
// MathEngine ã¢ãžã¥ãŒã«ãããšã¯ã¹ããŒããããåãšé¢æ°ãå©çš
Vector2D pos = makeVector(10.0f, 20.0f);
Vector2D vel = makeVector(1.0f, 2.0f);
Vector2D nextPos = pos + vel;
std::cout << "次ãã¬ãŒã 座æš: (" << nextPos.x << ", " << nextPos.y << ")\n";
// internalDistanceSquared(nextPos); // ã³ã³ãã€ã«ãšã©ãŒïŒã¢ãžã¥ãŒã«éå
¬éã·ã³ãã«ãªã®ã§åŒã¹ãªãïŒ
return 0;
}
M8.2 ãã«ãæéåçççž®ã®ã¡ã«ããºã ïŒBMI: Built Module InterfaceïŒ
ãªãã¢ãžã¥ãŒã«ã䜿ããšãã«ãæéã1/5ã1/10ã«æ¿æžããã®ãïŒãã€ããªäžé衚çŸã®ä»çµã¿ãåŠã³ãŸãã
ð§ ãã³ã®ã³å
茩
å
çãã¢ãžã¥ãŒã«ã䜿ããšãªããããªã«ã³ã³ãã€ã«ãéããªããã§ããïŒ
ð»ââïž ã·ãã¯ãå
ç
ãµãã£ãµãã£ãµãïŒåŸæ¥ã®ãããã¯æ¯ååå¥è§£æãšæ§æè§£æãè¡ã£ãŠãã£ãããã¢ãžã¥ãŒã«ã¯ååã³ã³ãã€ã«æã«ãBMIïŒBuilt Module Interface: .ifc ã .pcmïŒããšããæ§æè§£ææžã¿ãã€ããªã«å€æãããã®ããïŒ
ð ModulePartitionExample.ixx
// å€§èŠæš¡ãšã³ãžã³ãå°åãã«ããã¢ãžã¥ãŒã«ããŒãã£ã·ã§ã³ã®æ§æ
// 1. ããŒãã£ã·ã§ã³1: ã¬ã³ãã©ãŒ (Engine:Render)
export module Engine:Render;
export void renderFrame() { /* æç» */ }
// 2. ããŒãã£ã·ã§ã³2: ç©ç (Engine:Physics)
export module Engine:Physics;
export void updatePhysics(float dt) { /* ç©çæŒç® */ }
// 3. äž»ã¢ãžã¥ãŒã«ã€ã³ã¿ãŒãã§ãŒã¹: å
šããŒãã£ã·ã§ã³ãéçŽããŠå
Ž
export module Engine;
export import :Render;
export import :Physics;
// ããã«ãããå©çšåŽã¯ "import Engine;" ãšæžãã ãã§
// å
éšãåå²ããã巚倧ãšã³ãžã³ãç¬æã«ã€ã³ããŒãã§ããïŒ
M8.3 ã¬ã¬ã·ãŒãããããã¢ãžã¥ãŒã«ãžã®ç§»è¡ïŒããããŠããã import <header>ïŒ
æ¢åã®å·šå€§ãªã¬ã¬ã·ãŒã³ãŒãè³ç£ãäžåºŠã«æžãæããã®ã¯äžå¯èœã§ããæ®µéçã«ã¢ãžã¥ãŒã«åãããããããŠããããã®æŽ»çšæ³ãåŠã³ãŸãã
ð§ ãã³ã®ã³å
茩
å
çãä»ããäŒç€Ÿã®å€§èŠæš¡ãªã¬ã¬ã·ãŒã³ãŒãã«ã¯äœçŸåã .h ãã¡ã€ã«ããããã§ãããäžæ©ã§å
šéšã¢ãžã¥ãŒã«ã«æžãæãããªããŠäžå¯èœã§ãâŠâŠïŒ
ð»ââïž ã·ãã¯ãå
ç
ããã£ãšãããïŒããã§ C++20 ã«ã¯æ¢åã®ãããããã®ãŸãŸã¢ãžã¥ãŒã«ãšããŠã€ã³ããŒãã§ãããããããŠãããïŒHeader UnitsïŒããçšæãããŠããã®ããïŒ
ð HeaderUnitsMigration.cpp
// åŸæ¥ã® #include ã§ã¯ãªã import <...> ã§æ¢åã©ã€ãã©ãªãåã蟌ã
// ããã«ãããæ¢åããããã¢ãžã¥ãŒã«åæ§ã«äºåã³ã³ãã€ã«ããé«éåïŒ
import <iostream>;
import <vector>;
import <string>;
import <memory>;
// èªäœã®ã¬ã¬ã·ãŒããããããããŠããããšããŠå®å
šã«ã€ã³ããŒãå¯èœ
// import "LegacyMath.h";
int main() {
std::vector<std::string> logMessages;
logMessages.push_back("ããããŠãããã«ããè¶
é«éã³ã³ãã€ã«çšŒåäž");
for (const auto& msg : logMessages) {
std::cout << "[System] " << msg << "\n";
}
return 0;
}
M8.4 ã€ã³ããŒããŒçµ±åïŒèªäœã²ãŒã ãšã³ãžã³ã®ã¢ãžã¥ãŒã«åãšçŸä»£C++å®çµ
第1ç« ã®500è¡ã¹ãã²ãã£ã³ãŒãããå§ãŸã£ãæ
ããC++20ã¢ãžã¥ãŒã«ã«ãã£ãŠåçšã¬ãã«ã®çŸä»£ã²ãŒã ãšã³ãžã³ãžãšæè¯ããŸãã
ð»ââïž ã·ãã¯ãå
ç
ãã³ã®ã³åãæ¯ãè¿ã£ãŠã¿ãïŒãã®ç¬¬1ç« ã®ã°ããŒãã«å€æ°ã ããã®ã¹ãã²ãã£ã³ãŒãããããªããžã§ã¯ãæåãRAIIããã¶ã€ã³ãã¿ãŒã³ãCRTPãç¬èªã¡ã¢ãªããŒã«ãåºå®ãã«ã¿ã¿ã€ã ããããŠã³ã«ãŒãã³ãã³ã³ã»ãããRangesãã¢ãžã¥ãŒã«ãŸã§âŠâŠåã¯C++ã®æŽå²ãšé²åã®ãã¹ãŠãèžç Žããã®ããïŒ
ð§ ãã³ã®ã³å
茩
ãã³å
çãæ¬åœã«ããããšãããããŸããïŒããªããã®æ©èœãå¿
èŠãªã®ãããå€ãæžãæ¹ã®äœãèŠããã£ãã®ããã身ããã£ãŠäœéšãããããããã¢ãã³C++ã®èšèšææ³ãè¡èãšãªã£ãŠèº«ã«ã€ããŸããïŒ
ð ModernGameEngineArchitecture.cpp
// C++20 ã¢ãã³ã²ãŒã ãšã³ãžã³å®æåœ¢éªšæ Œ
// (å®éã®ã¢ãžã¥ãŒã«ç°å¢ã§ã¯ export module ShirokumaGame; ãšããŠå®çŸ©)
#include <iostream>
#include <vector>
#include <string>
#include <concepts>
#include <ranges>
// ã³ã³ã»ããã«ããåå¶çŽ
template <typename T>
concept UpdatableEntity = requires(T a, float dt) {
a.update(dt);
{ a.isAlive() } -> std::same_as<bool>;
};
// ã²ãŒã ãšã³ãã£ãã£
class SpaceInvader {
public:
SpaceInvader(std::string name, int hp) : name_(std::move(name)), hp_(hp) {}
void update(float dt) { (void)dt; }
bool isAlive() const { return hp_ > 0; }
const std::string& getName() const { return name_; }
int getHp() const { return hp_; }
private:
std::string name_;
int hp_;
};
// ãšã³ãžã³ã³ã¢
class ModernInvaderEngine {
public:
void addEntity(SpaceInvader entity) {
entities_.push_back(std::move(entity));
}
void runFrame(float dt) {
// C++20 Ranges ãã€ãã©ã€ã³ã«ããçåãšã³ãã£ãã£ã®é«éãã£ã«ã¿ãªã³ã°
auto aliveEntities = entities_
| std::views::filter(&SpaceInvader::isAlive);
for (auto& entity : aliveEntities) {
entity.update(dt);
}
}
void printStatus() const {
std::cout << "=== Shirokuma Modern Engine 皌åã¹ããŒã¿ã¹ ===\n";
for (const auto& e : entities_) {
std::cout << " æ©äœ: " << e.getName() << " (HP: " << e.getHp() << ")\n";
}
}
private:
std::vector<SpaceInvader> entities_;
};
int main() {
ModernInvaderEngine engine;
engine.addEntity(SpaceInvader("è¿ææ¯èŠã·ãã¯ãå·", 1000));
engine.addEntity(SpaceInvader("çªæãããŒã³A", 50));
engine.addEntity(SpaceInvader("çªæãããŒã³B", 0)); // æç Žæžã¿
engine.runFrame(1.0f / 60.0f);
engine.printStatus();
std::cout << "\nð [CONGRATULATIONS] ã¢ãã³C++ã³ãŒã¹ïŒM1ãM8ïŒå
šèª²çšä¿®äºïŒ\n";
return 0;
}
ð¡ ãã®ã»ã¯ã·ã§ã³ã®éèŠãã€ã³ã
- èœãšã穎1ïŒã¢ãžã¥ãŒã«å
ã§ã®ãã¯ãã®ãšã¯ã¹ããŒãäžå¯èœæ§: `#define` ã§å®çŸ©ããããã¯ãã¯ã¢ãžã¥ãŒã«ãã export ã§ããŸããïŒããã¯ãã°ã§ã¯ãªãããã¯ãæ±æãé²ãããã®æå³çãªä»æ§ã§ãïŒã宿°ã¯ `export constexpr`ãåæäœã¯ `export template` ã `concept`ã颿°ã¯ `export inline` ãçšããŠãèšèªæ©èœã§è¡šçŸããŠãã ããã
- èœãšã穎2ïŒãã«ãã·ã¹ãã ïŒCMake / Ninja / Visual StudioïŒã®å¯Ÿå¿äŸå: C++20 ã¢ãžã¥ãŒã«ã¯ãœãŒã¹ãã¡ã€ã«éã®ãäŸåã°ã©ãããã³ã³ãã€ã«åã«èµ°æ»ããŠãã«ãé åºãåçã«æ±ºå®ããå¿
èŠããããŸããCMake 3.28+ãNinja 1.11+ãMSVC 19.34+ / Clang 16+ ãªã©ãã¢ãžã¥ãŒã«ã®èªåã¹ãã£ã³ã«å¯Ÿå¿ããææ°ããŒã«ãã§ãŒã³ã䜿çšããŠãã ããã
- èœãšã穎3ïŒåŸªç°ã€ã³ããŒãïŒCircular Module DependencyïŒã®çŠæ¢: ã¢ãžã¥ãŒã«Aãã¢ãžã¥ãŒã«Bã import ããã¢ãžã¥ãŒã«Bãã¢ãžã¥ãŒã«Aã import ããããšã¯èšèªä»æ§ã§çŠæ¢ãããŠããŸãã埪ç°äŸåãçºçããå Žåã¯ãå
±éã€ã³ã¿ãŒãã§ãŒã¹ãå¥ã®ã¢ãžã¥ãŒã«ãŸãã¯ã¢ãžã¥ãŒã«ããŒãã£ã·ã§ã³ãžåãåºããŠãã ããã
ð ç解床ãã§ãã¯ã¯ã€ãº
Q1. C++20 ã¢ãžã¥ãŒã«ã«ãããŠãã·ã³ãã«ãã¢ãžã¥ãŒã«å€éšãžå
¬éããããã«å
é ã«ä»äžããããŒã¯ãŒãã¯ã©ãã§ããïŒ
- 1. export
- 2. public
- 3. extern
- 4. visible
æ£è§£ãšè§£èª¬ãèŠã
æ£è§£ïŒexport
æ£è§£ã¯ export ã§ãïŒã¢ãžã¥ãŒã«å®£èš `export module ã¢ãžã¥ãŒã«å;` ã®äžã§ãå€éšãžå
¬éãããã¯ã©ã¹ã颿°ã倿°ãã³ã³ã»ãããªã©ã®å®£èšã®å
é ã« `export` ãä»äžããŸããexport ã®ã€ããŠããªãã·ã³ãã«ã¯ã¢ãžã¥ãŒã«å
éšå°çšãšããŠåŒ·åã«ã«ãã»ã«åãããŸãã
Q2. åŸæ¥ã® `#include` ãšæ¯èŒãããC++20 ã¢ãžã¥ãŒã«ã®ããã¯ãïŒ#defineïŒãã«é¢ããæåã®éããšããŠæ£ãããã®ã¯ã©ãã§ããïŒ
- 1. ã¢ãžã¥ãŒã«å
ã§å®çŸ©ããããã¯ãã¯ãã€ã³ããŒããããã¡ã€ã«ãžèªåçã«ãã¹ãŠæŒæŽ©ã»äŒæãã
- 2. ã¢ãžã¥ãŒã«å
ã§å®çŸ©ããããã¯ãã¯å€éšãžäžåæŒæŽ©ãããã€ã³ããŒãåŽãæ±æããããšããªã
- 3. ã¢ãžã¥ãŒã«ã䜿ããšãC++ããã°ã©ã å
ã§ãã¯ãã®äœ¿çšãäžåçŠæ¢ããã
- 4. ãã¯ãã¯èªåçã« constexpr 倿°ãžèªå倿ããã
æ£è§£ãšè§£èª¬ãèŠã
æ£è§£ïŒã¢ãžã¥ãŒã«å
ã§å®çŸ©ããããã¯ãã¯å€éšãžäžåæŒæŽ©ãããã€ã³ããŒãåŽãæ±æããããšããªã
æ£è§£ã¯ãã¢ãžã¥ãŒã«å
ã§å®çŸ©ããããã¯ãã¯å€éšãžäžåæŒæŽ©ãããã€ã³ããŒãåŽãæ±æããããšããªããã§ãïŒåŸæ¥ã® #include ã§ã¯ windows.h ãªã©ã®ãã¯ããåæã«åŸç¶ã³ãŒããç Žå£ããäºæ
ãå€çºããŠããŸããããã¢ãžã¥ãŒã«ã§ã¯ãã¯ããå¢çãè¶ããŠæŒããããšãåççã«ãªããªããŸããã
Q3. C++20 ã¢ãžã¥ãŒã«ã«ãããŠãå€§èŠæš¡ãªåäžã¢ãžã¥ãŒã«ãè€æ°ã®ãã¡ã€ã«ã«åå²ããŠéçºããããã®æ©èœã¯ã©ãã§ããïŒ
- 1. ã¢ãžã¥ãŒã«ããŒãã£ã·ã§ã³ïŒModule PartitionïŒ
- 2. ã¢ãžã¥ãŒã«ãã©ã°ã¡ã³ãïŒModule FragmentïŒ
- 3. ãã«ãã¹ã¬ããã€ã³ã¯ã«ãŒãïŒMulti-thread IncludeïŒ
- 4. ããªã³ã³ãã€ã«ãããïŒPCHïŒ
æ£è§£ãšè§£èª¬ãèŠã
æ£è§£ïŒã¢ãžã¥ãŒã«ããŒãã£ã·ã§ã³ïŒModule PartitionïŒ
æ£è§£ã¯ãã¢ãžã¥ãŒã«ããŒãã£ã·ã§ã³ïŒModule PartitionïŒãã§ãïŒ`export module Engine:Physics;` ã®ããã«ã³ãã³ `:` ãçšããŠãµãåäœãå®çŸ©ããäž»ã¢ãžã¥ãŒã«ããéçŽããŠãšã¯ã¹ããŒãããããšã§ã巚倧ãªã¢ãžã¥ãŒã«ãè€æ°äººã§äžŠè¡éçºã§ããŸãã
ð»ââïž ã·ãã¯ãC++ã©ã ã€ã³ã¿ã©ã¯ãã£ãåŠç¿ã·ã¹ãã
ãã©ãŠã¶ã§JavaScriptãæå¹ã«ãããšããã©ãŠã¶å
ã€ã³ããŒããŒã²ãŒã ãšãã¥ã¬ãŒã¿ãã¡ã¢ãªãããå¯èŠåãUMLã¯ã©ã¹å³ã察話å解説ãç解床ã¯ã€ãºãèµ·åããŸãã
ã€ã³ã¿ã©ã¯ãã£ãåŠç¿ãéå§ãã â