C++のような機能が豊富な言語で作業する際は、オーバーエンジニアリングに注意することが重要です。オーバーエンジニアリングは、開発者が問題に対して過度に複雑または不要なソリューションを導入したときに発生します。
C++開発者は、最近の標準で導入された新機能をできるだけ多く使いたくなるかもしれませんが、それは最終的にコードを必要以上に複雑にする可能性があります。
C++メタプログラミングを使用して、コンパイル時に評価される算術演算を持つ型消去コンテナを作成する例を次に示します。この例はC++メタプログラミング手法のパワーと柔軟性を示していますが、テンプレート、コンセプト、constexpr関数の使用により複雑に見えるかもしれません。
#include <iostream>
#include <type_traits>
template<typename T>
concept Arithmetic = std::is_arithmetic_v<T>;
template<Arithmetic T>
struct AnyType {
constexpr AnyType(const T& value) : value_(value) {}
template<Arithmetic U>
constexpr auto add(const AnyType<U>& other) const {
return AnyType{ value_ + other.value_ };
}
template<Arithmetic U>
constexpr auto subtract(const AnyType<U>& other) const {
return AnyType{ value_ - other.value_ };
}
template<Arithmetic U>
constexpr auto multiply(const AnyType<U>& other) const {
return AnyType{ value_ * other.value_ };
}
template<Arithmetic U>
constexpr auto divide(const AnyType<U>& other) const {
static_assert(other.value_ != 0, "Division by zero");
return AnyType{ value_ / other.value_ };
}
template<Arithmetic U>
friend std::ostream& operator<<(std::ostream& os, const AnyType<U>& any) {
return os << any.value_;
}
private:
T value_;
};
int main() {
constexpr AnyType<int> x{ 5 };
constexpr AnyType<float> y{ 2.5f };
constexpr auto addition = x.add(y);
constexpr auto subtraction = x.subtract(y);
constexpr auto multiplication = x.multiply(y);
constexpr auto division = x.divide(y);
std::cout << "Addition: " << addition << std::endl;
std::cout << "Subtraction: " << subtraction << std::endl;
std::cout << "Multiplication: " << multiplication << std::endl;
std::cout << "Division: " << division << std::endl;
return 0;
}
この例では:
- テンプレートパラメータを算術型に制約するためのコンセプト
Arithmeticを定義します。 - 任意の算術型を保持するために
AnyTypeクラステンプレートが定義されます。 - 潜在的に異なる型の
add、subtract、multiply、divideオブジェクト間で算術演算を実行するメンバー関数(AnyType)を提供します。 - We use
constexprを使用して、これらの操作がコンパイル時に評価されることを保証します。 - We overload the
operator<<をオーバーロードして、AnyTypeオブジェクトをstd::ostreamに出力できるようにします。
確かに、特定のニーズにはこのようなコードが役立つことがあります。しかし一般的に、基本的な算術演算を実行するために、本当にそのような洗練されたクラスが必要でしょうか?ハエを殺すために戦車を造るようなものです:)
要約すると、洗練された新機能に誘惑されることを避け、実際に必要な場合にのみそれらを使用してください。そして常に KISSとYAGNIの原則に従う:
Keep It Simple, Stupid(KISS)とYou Ain't Gonna Need It(YAGNI)は、シンプルさを提唱し、必要になるまで不要な機能を避けることを説く原則です。
