よく似てはいるものの、異なる構造体/クラスの間で値をやり取りすることを考えるので、正しくは「代入」ではないんですが、ここでは「代入」ということばを使うことにします。
たとえば、どこかでこういった構造体が定義されていたとします。
#include <cstdlib> static const std::size_t MAX_LENGTH = 16; struct HisStructure { std::size_t length; char value[MAX_LENGTH + 1]; };
自分で作ったこういうクラスがあるとします。
#include <string> class MyClass { public: MyClass() : value_() {} MyClass(const std::string& value) : value_(value) {} void setValue(const std::string& value) { value_ = value; } const std::string& getValue() const { return value_; } MyClass& operator = (const HisStructure& hisStructure) { setValue(std::string(hisStructure.value, hisStructure.length)); return *this; } private: std::string value_; };
すでにコードに現れていますが、HisStructure
→ MyClass
という代入は、MyClass
に代入演算子を定義することで可能になります。
HisStructure hisStructure = { 10, "abcdefghij" }; MyClass myClass; // OK myClass = hisStructure;
逆にMyClass
→ HisStructure
という代入をやってみます。
「左値」を表すクラスを定義します。
template<typename T> class LValue { public: explicit LValue(T& lvalue) : lvalue_(lvalue) {} template<typename U> T& operator = (const U& rhs) { Assignment<T, U>::exec(lvalue_, rhs); return lvalue_; } private: T& lvalue_; };
ここでAssignment
は次のような構造体テンプレートです。構造体とは言いつつ、欲しいのはexec
という関数だけなんですが。関数テンプレートは特殊化ができないのでこうやって構造体テンプレートのメンバとして定義しています。
template<typename T, typename U> struct Assignment { static T& exec(const U& rhs); };
LValueを返す関数テンプレートを書きます。
template<typename T> LValue<T> lvalue(T& lvalue) { return LValue<T>(lvalue); }
MyClass
からHisStructure
へ値を移す関数(特殊化した構造体とそのメンバ関数)を書きます。
#include <cstring> #include <algorithm> template<> struct Assignment<HisStructure, MyClass> { static HisStructure& exec(HisStructure& lhs, const MyClass& rhs) { lhs.length = std::min(rhs.getValue().size(), MAX_LENGTH); std::memcpy(lhs.value, rhs.getValue().c_str(), lhs.length); return lhs; } };
代入操作です。慣れないとちょっと面妖かもしれません。
MyClass myClass("0123456789"); HisStructure hisStructure = { 0, "" }; // OK lvalue(hisStructure) = myClass;
LValueクラス、lvalue関数、Assignment構造体を事前に用意しておけば、特殊化したAssignment構造体を書くことで代入OKになります。