boost sg msgpack
TRANSCRIPT
![Page 1: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/1.jpg)
MessagePackとAPIバージョニング
近藤 貴俊
2015/5/29 1 Copyright OGIS-RI 2015
![Page 2: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/2.jpg)
• 近藤貴俊
• 株式会社オージス総研 – IoT分野でMessagePackを利用した データの収集、制御を行う プラットフォームを開発している
• msgpack-c コミッタの一人 – 後述するMessagePackフォーマットを扱うための
C/C++ 実装
– C++版は Cのwrapperではない
• C++Nowに ここ6年くらい 連続参加中
2015/5/29 Copyright OGIS-RI 2015 2
自己紹介
![Page 3: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/3.jpg)
2015/5/29 Copyright OGIS-RI 2015 3
MessagePackとは
![Page 4: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/4.jpg)
2015/5/29 Copyright OGIS-RI 2015 4
MessagePackとは
![Page 5: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/5.jpg)
2015/5/29 Copyright OGIS-RI 2015 5
MessagePackとは
![Page 6: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/6.jpg)
2015/5/29 Copyright OGIS-RI 2015 6
MessagePackとは
![Page 7: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/7.jpg)
2015/5/29 Copyright OGIS-RI 2015 7
MessagePackとは
![Page 8: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/8.jpg)
2015/5/29 Copyright OGIS-RI 2015 8
MessagePackとは
![Page 9: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/9.jpg)
2015/5/29 Copyright OGIS-RI 2015 9
MessagePackとは
https://github.com/msgpack/msgpack/blob/master/spec.md
![Page 10: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/10.jpg)
• Website http://msgpack.org/
• JSONと同様
– ポータブル
– 基本的な型情報を内包
– コンポジットなデータ構造(詳細は次ページで)
• JSONとの違い
– サイズが小さい
– バイナリフォーマット
– バイナリデータもそのまま扱える
– 整数と浮動小数点数を区別
– Parseが容易で計算負荷が小さい
2015/5/29 Copyright OGIS-RI 2015 10
MessagePackとは?
![Page 11: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/11.jpg)
2015/5/29 Copyright OGIS-RI 2015 11
MessagePackとは?
msgpack::object
nil boolean u64 i64 f64
str bin ext array map
*
*
double, float
object_kv
key val
※ クラス名は msgpack-c の名称で記載
![Page 12: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/12.jpg)
MessagePackをサポートする言語
2015/5/29 Copyright OGIS-RI 2015 12
![Page 13: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/13.jpg)
MessagePackをサポートする言語
2015/5/29 Copyright OGIS-RI 2015 13
このリストは github から自動収集して生成されているため どのレベルで実装されているかは要確認
![Page 14: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/14.jpg)
2015/5/29 Copyright OGIS-RI 2015 14
msgpack-c 中でも、C++にフォーカスをあてた内容で、
Cには当てはまらない内容もあるので注意
![Page 15: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/15.jpg)
Pack/Unpack
2015/5/29 15
#include <tuple> #include <string> #include <sstream> #include <msgpack.hpp> int main() { auto t1 = std::make_tuple("hello", true, 42, 12.3); std::stringstream ss; msgpack::pack(ss, t1); msgpack::unpacked unpacked = msgpack::unpack(ss.str().data(), ss.str().size()); msgpack::object obj = unpacked.get(); auto t2 = obj.as<std::tuple<std::string, bool, int, double>>(); assert(t1 == t2); }
write(const char*, std::size_t) メンバ関数を持つ、任意の型
Copyright OGIS-RI 2015
pack
unpack
convert
![Page 16: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/16.jpg)
C++/object/byte stream
2015/5/29 16 Copyright OGIS-RI 2015
C++ Types
msgpack::object
Byte stream
pack object
pack unpack
convert
adaptor
![Page 17: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/17.jpg)
Adaptor
2015/5/29 17 Copyright OGIS-RI 2015
https://github.com/msgpack/msgpack-c/wiki/v1_1_cpp_adaptor
C++ type msgpack::object type
bool bool
char* str
std::deque array
char positive/negative integer
signed ints *1 positive/negative integer
unsigned ints *2 positive integer
std::list array
std::map array
std::pair array
std::set array
std::string str
std::vector array
std::vector<char> bin
*1 signed ints signed char, signed short, signed int, signed long, signed long long *2 unsigned ints unsigned char, unsigned short, unsigned int, signed long, signed long long
C++11 type msgpack::object type
std::array array
std::array<char> bin
std::forward_list array
std::tuple array
std::array array
std::unordered_map array
std::unordered_set array
boost type msgpack::object type
boost::optional<T> T
boost::string_ref str
![Page 18: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/18.jpg)
自前のクラスのmsgpack対応
2015/5/29 18 Copyright OGIS-RI 2015
https://github.com/msgpack/msgpack-c/wiki/v1_1_cpp_adaptor
#include <msgpack.hpp> struct your_class { int a; std::string b; MSGPACK_DEFINE(a, b); };
intrusive
![Page 19: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/19.jpg)
自前のクラスのmsgpack対応
2015/5/29 19 Copyright OGIS-RI 2015
https://github.com/msgpack/msgpack-c/wiki/v1_1_cpp_adaptor
#include <msgpack.hpp> struct my { int a; std::string b; }; namespace msgpack { template <typename Stream> inline packer<Stream>& operator<< (packer<Stream>& o, const my& v) { o.pack_array(2); o << v.a; o << v.b; return o; } } // namespace msgpack
non-intrusive
![Page 20: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/20.jpg)
ADLを用いたアダプタの実現
2015/5/29 20 Copyright OGIS-RI 2015
namespace msgpack { template <typename Stream> class packer { public: packer(Stream&) {} template <typename T> packer<Stream>& pack(const T& v) { *this << v; return *this; } }; // Default behavior template <typename Stream, typename T> inline packer<Stream>& operator<< (packer<Stream>& o, const T&) { std::cout << "Default serialize" << std::endl; return o; } // API template <typename Stream, typename T> inline void pack(Stream& s, const T& v) { packer<Stream>(s).pack(v); } } // namespace msgpack
int main() { std::stringstream ss; msgpack::pack(ss, 1); msgpack::pack(ss, 1.2); }
http://melpon.org/wandbox/permlink/L0WpfUz2hSUZ3ItM
version 0.5.9 まで
![Page 21: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/21.jpg)
ADLを用いたアダプタの実現
2015/5/29 21 Copyright OGIS-RI 2015
namespace msgpack { template <typename Stream> class packer { public: packer(Stream&) {} template <typename T> packer<Stream>& pack(const T& v) { *this << v; return *this; } }; // Default behavior template <typename Stream, typename T> inline packer<Stream>& operator<< (packer<Stream>& o, const T&); // User defined adaptor template <typename Stream> inline packer<Stream>& operator<< (packer<Stream>& o, int) { std::cout << "Int serialize" << std::endl; return o; } } // namespace msgpack
int main() { std::stringstream ss; msgpack::pack(ss, 1); msgpack::pack(ss, 1.2); }
http://melpon.org/wandbox/permlink/L0WpfUz2hSUZ3ItM
version 0.5.9 まで
ユーザ定義のoperator<<オーバーロード
![Page 22: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/22.jpg)
APIのバージョニング
2015/5/29 22 Copyright OGIS-RI 2015
• msgpack-c の C++版はヘッダオンリーライブラリとなった
• ヘッダオンリーライブラリであっても、古いABIのmsgpack-c をincludeして作ったライブラリ(.a , .LIBなど)を、 新しいABIのmsgpack-cと合わせて使うと問題が生じる – std::listのサイズをO(1)で求めることになった際にも 同様の問題が発生した
• これを防ぐために、ABIに変更が生じた場合、 古いバージョンはそのまま使い続けられるようにしたい
• ABIに関わらないバグフィックスなどは 古いバージョンにも反映していきたい
msgpack.hpp
userlib.cpp libuser.a
msgpack.hpp
client.cpp include
生成 include
link
![Page 23: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/23.jpg)
APIのバージョニング
2015/5/29 23 Copyright OGIS-RI 2015
Inline namespace The inline namespace mechanism is intended to support library evolution by providing a mechanism that support a form of versioning. Consider: inline namespace V99 { void f(int); // does something better than the V98 version void f(double); // new feature // ... } namespace V98 { void f(int); // does something // ... } namespace Mine { #include "V99.h" #include "V98.h" }
We here have a namespace Mine with both the latest release (V99) and the previous one (V98). If you want to be specific, you can: #include "Mine.h" using namespace Mine; V98::f(1); // old version V99::f(1); // new version f(1); // default version
The point is that the inline specifier makes the declarations from the nested namespace appear exactly as if they had been declared in the enclosing namespace.This is a very ``static'' and implementer-oriented facility in that the inline specifier has to be placed by the designer of the namespaces -- thus making the choice for all users. It is not possible for a user of Mine to say ``I want the default to be V98rather than V99.''
file V99.h
file V98.h
file Mine.h
http://www.stroustrup.com/C++11FAQ.html#inline-namespace
![Page 24: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/24.jpg)
APIのバージョニング
2015/5/29 24 Copyright OGIS-RI 2015
#include <iostream> namespace msgpack { // lib code v1 inline namespace v1 { inline void foo() { std::cout << "v1::foo()" << std::endl; } inline void bar() { std::cout << "v1::bar()" << std::endl; foo(); // A msgpack::foo(); // B msgpack::v1::foo(); // C } } } // client code int main() { std::cout << "msgpack::bar();" << std::endl; msgpack::bar(); std::cout << "msgpack::v1::bar();" << std::endl; msgpack::v1::bar(); } http://melpon.org/wandbox/permlink/ncTAeERuXByq80Y3
msgpack::bar(); v1::bar() v1::foo() v1::foo() v1::foo() msgpack::v1::bar(); v1::bar() v1::foo() v1::foo() v1::foo()
![Page 25: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/25.jpg)
APIのバージョニング
2015/5/29 25 Copyright OGIS-RI 2015
namespace msgpack { namespace v1 { void bar(); } inline namespace v2 { using v1::bar; void foo() { std::cout << "v2::foo()" << std::endl; } } namespace v1 { void foo() { std::cout << "v1::foo()" << std::endl; } void bar() { std::cout << "v1::bar()" << std::endl; foo(); // A bar()が定義されている名前空間v1のfoo()が呼び出される
msgpack::foo(); // B v2のfoo()が呼び出される
msgpack::v1::foo(); // C 明示的に指定された名前空間のfoo()が呼び出される
} } } http://melpon.org/wandbox/permlink/8HBPTxCmuTiuluaz
msgpack::bar(); v1::bar() v1::foo() v2::foo() v1::foo() msgpack::v1::bar(); v1::bar() v1::foo() v2::foo() v1::foo()
BとCを上手く使い分けることでバージョニングを実現
![Page 26: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/26.jpg)
APIのバージョニング
2015/5/29 26 Copyright OGIS-RI 2015
A
B
C
msgpack::B()
msgpack::C()
V1
D
msgpack::D()
inline namespace
![Page 27: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/27.jpg)
APIのバージョニング
2015/5/29 27 Copyright OGIS-RI 2015
A
B
C
A
ABI変更
msgpack::B()
msgpack::C()
V1 V2
D
msgpack::D()
msgpack::B()
inline namespace
using v1::B using V1::C using v1::D
![Page 28: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/28.jpg)
using v1::B using V1::C using v1::D
APIのバージョニング
2015/5/29 28 Copyright OGIS-RI 2015
A
B
C
A
C
ABI変更
msgpack::B()
msgpack::C()
V1 V2 V3
D
msgpack::D()
msgpack::B()
inline namespace
msgpack::D() using v2::D
![Page 29: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/29.jpg)
using v1::B using V1::C using v1::D
APIのバージョニング
2015/5/29 29 Copyright OGIS-RI 2015
A
B
C
A
C
ABI変更
msgpack::B()
msgpack::C()
V1 V2 V3
D
msgpack::D()
msgpack::B()
inline namespace
msgpack::D() using v2::D
![Page 30: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/30.jpg)
using v1::B using V1::C using v1::D
APIのバージョニング
2015/5/29 30 Copyright OGIS-RI 2015
A
B'
C
A
C
ABI変更
msgpack::B()
msgpack::C()
V1 V2 V3
D
msgpack::D()
msgpack::B()
inline namespace
msgpack::D() using v2::D
CのABI変更対応
![Page 31: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/31.jpg)
using v1::B using V1::C using v1::D
APIのバージョニング
2015/5/29 31 Copyright OGIS-RI 2015
A
B'
C
A
C
ABI変更
msgpack::B()
msgpack::C()
V1 V2 V3
D
msgpack::D()
msgpack::B()
inline namespace
msgpack::D()
using v2::A using v2::B using v2::D
CのABI変更対応
B'のABIに変更が無ければこれでOK
![Page 32: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/32.jpg)
using v1::B using V1::C using v1::D
APIのバージョニング
2015/5/29 32 Copyright OGIS-RI 2015
A
B'
C
A
C
ABI変更
msgpack::B()
msgpack::C()
V1 V2 V3
D
msgpack::D()
msgpack::B()
inline namespace
msgpack::D()
using v2::A using v2::B using v2::D
B'のABIに変更が生じる場合
CのABI変更対応
![Page 33: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/33.jpg)
using v1::B using V1::C using v1::D
APIのバージョニング
2015/5/29 33 Copyright OGIS-RI 2015
A
B''
C
A
C
ABI変更
msgpack::B()
msgpack::v1::C()
V1 V2 V3
D
msgpack::D()
msgpack::B()
inline namespace
msgpack::バージョン名前空間:: 修飾することで 明示的に特定バージョンの名前空間を参照
msgpack::名前空間修飾することで inline namespaceを参照
msgpack::D() using v2::D
CのABI変更対応 をここでは行わない
![Page 34: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/34.jpg)
using v1::B using V1::C using v1::D
APIのバージョニング
2015/5/29 34 Copyright OGIS-RI 2015
A
B''
C
A
C
ABI変更
msgpack::B()
V1 V2 V3
D
msgpack::D()
B msgpack::B()
inline namespace
msgpack::v1::C()
msgpack::D()
msgpack::C()
using v2::D
CのABI変更対応
ABI変更
![Page 35: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/35.jpg)
using v1::B using V1::C using v1::D
APIのバージョニング
2015/5/29 35 Copyright OGIS-RI 2015
A
B''
C
A
C
ABI変更
msgpack::B()
V1 V2 V3
D
msgpack::D()
B
CのABI変更対応
msgpack::B()
inline namespace
msgpack::v1::C()
msgpack::D()
msgpack::C()
using v2::D
ABI変更
![Page 36: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/36.jpg)
using v1::B using V1::C using v1::D
APIのバージョニング
2015/5/29 36 Copyright OGIS-RI 2015
A'
B''
C
A'
C
ABI変更
msgpack::B()
V1 V2 V3
D
msgpack::D()
B
CのABI変更対応
msgpack::B()
inline namespace
msgpack::v1::C()
msgpack::D()
msgpack::C()
using v2::D
ABI変更 BのABI変更対応 BのABI変更対応
![Page 37: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/37.jpg)
using v1::B using V1::C using v1::D
APIのバージョニング
2015/5/29 37 Copyright OGIS-RI 2015
A'
B''
C
A'
C
ABI変更
msgpack::B()
V1 V2 V3
D
msgpack::D()
B
CのABI変更対応
msgpack::B()
inline namespace
msgpack::v1::C()
msgpack::D()
msgpack::C()
using v2::A using v2::D
ABI変更 BのABI変更対応 BのABI変更対応
A'のABIに変更が無ければこれでOK
![Page 38: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/38.jpg)
using v1::B using V1::C using v1::D
APIのバージョニング
2015/5/29 38 Copyright OGIS-RI 2015
A''
B'
C
A''
C
ABI変更
V1 V2 V3
D
msgpack::D()
B
ABI変更対応 A
inline namespace
msgpack::v1::C()
msgpack::v1::B()
msgpack::v1::B()
msgpack::D()
msgpack::C()
msgpack::B()
using v1::D
A'のABIに変更がある場合
![Page 39: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/39.jpg)
ADL問題
2015/5/29 39 Copyright OGIS-RI 2015
namespace msgpack { template <typename Stream> class packer { public: packer(Stream&) {} template <typename T> packer<Stream>& pack(const T& v) { *this << v; return *this; } }; // Default behavior template <typename Stream, typename T> inline packer<Stream>& operator<< (packer<Stream>& o, const T&) { std::cout << "Default serialize" << std::endl; return o; } // API template <typename Stream, typename T> inline void pack(Stream& s, const T& v) { packer<Stream>(s).pack(v); } } // namespace msgpack
int main() { std::stringstream ss; msgpack::pack(ss, 1); msgpack::pack(ss, 1.2); }
http://melpon.org/wandbox/permlink/L0WpfUz2hSUZ3ItM
msgpack::operator(*this, v); と書かなければ、inline namespaceは 参照されない
![Page 40: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/40.jpg)
ADL問題
2015/5/29 40 Copyright OGIS-RI 2015
namespace msgpack { template <typename Stream> class packer { public: packer(Stream&) {} template <typename T> packer<Stream>& pack(const T& v) { msgpack::operator<<(*this, v); return *this; } }; // Default behavior template <typename Stream, typename T> inline packer<Stream>& operator<< (packer<Stream>& o, const T&) { std::cout << "Default serialize" << std::endl; return o; } // API template <typename Stream, typename T> inline void pack(Stream& s, const T& v) { packer<Stream>(s).pack(v); } } // namespace msgpack
int main() { std::stringstream ss; msgpack::pack(ss, 1); msgpack::pack(ss, 1.2); }
http://melpon.org/wandbox/permlink/WlEDZo53McLh61AT
error: no member named 'operator<<' in namespace 'msgpack'
![Page 41: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/41.jpg)
ADL問題
2015/5/29 41 Copyright OGIS-RI 2015
namespace msgpack { template <typename Stream> class packer { public: packer(Stream&) {} template <typename T> packer<Stream>& pack(const T& v) { msgpack::operator<<(*this, v); return *this; } }; // Default behavior template <typename Stream, typename T> inline packer<Stream>& operator<< (packer<Stream>& o, const T&) { std::cout << "Default serialize" << std::endl; return o; } // API template <typename Stream, typename T> inline void pack(Stream& s, const T& v) { packer<Stream>(s).pack(v); } } // namespace msgpack
template <typename Stream> class packer; template <typename Stream, typename T> packer<Stream>& operator<< (packer<Stream>& o, const T&);
http://melpon.org/wandbox/permlink/Mkp68SjWv9jsEqlD
先行宣言を入れてみると。。。
![Page 42: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/42.jpg)
ADL問題
2015/5/29 42 Copyright OGIS-RI 2015
namespace msgpack { template <typename Stream> class packer { public: packer(Stream&) {} template <typename T> packer<Stream>& pack(const T& v) { msgpack::operator<<(*this, v); return *this; } }; // Default behavior template <typename Stream, typename T> inline packer<Stream>& operator<< (packer<Stream>& o, const T&){...} // User defined adaptor template <typename Stream> inline packer<Stream>& operator<< (packer<Stream>& o, int) { std::cout << "Int serialize" << std::endl; return o; } } // namespace msgpack
http://melpon.org/wandbox/permlink/Mkp68SjWv9jsEqlD
template <typename Stream> class packer; template <typename Stream, typename T> packer<Stream>& operator<< (packer<Stream>& o, const T&);
int main() { std::stringstream ss; msgpack::pack(ss, 1); msgpack::pack(ss, 1.2); }
ユーザ定義のオーバーロードが呼ばれない
![Page 43: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/43.jpg)
ADL問題
2015/5/29 43 Copyright OGIS-RI 2015
namespace msgpack { template <typename Stream> class packer { public: packer(Stream&) {} template <typename T> packer<Stream>& pack(const T& v) { msgpack::operator<<(*this, v); return *this; } }; // Default behavior template <typename Stream, typename T> inline packer<Stream>& operator<< (packer<Stream>& o, const T&){...} // User defined adaptor template <typename Stream> inline packer<Stream>& operator<< (packer<Stream>& o, int) { std::cout << "Int serialize" << std::endl; return o; } } // namespace msgpack
http://melpon.org/wandbox/permlink/tE5b4taP6cQPicXb
template <typename Stream> class packer; template <typename Stream, typename T> packer<Stream>& operator<< (packer<Stream>& o, const T&); template <typename Stream> packer<Stream>& operator<< (packer<Stream>& o, int);
int main() { std::stringstream ss; msgpack::pack(ss, 1); msgpack::pack(ss, 1.2); }
ユーザ定義のオーバーロードの先行宣言を入れると 期待通りディスパッチされる
![Page 44: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/44.jpg)
ADL問題
2015/5/29 44 Copyright OGIS-RI 2015
msgpackの先行宣言群
ユーザの先行宣言群
msgpackのライブラリ本体
ユーザのコード本体
#include <msgpack_fwd.hpp>
#include <msgpack.hpp>
user.cpp
このアプローチの行き着く先にあるもの
ユーザコードの書き方に大きな制約を課してしまう
![Page 45: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/45.jpg)
なにが問題なのか?
2015/5/29 45 Copyright OGIS-RI 2015
• オーバーロードによるアダプタの実現
– オーバーロードは、呼び出しコードがinstantiateした際、 そこから見えている関数が候補となる
– ADLによって、呼び出しコードのinstantiate を遅延
– ADLを使うためには、名前空間修飾してはならない
• APIバージョニングの実現
– 名前空間修飾しないとAPIバージョニングできない
• この2つの相性が悪い
![Page 46: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/46.jpg)
オーバーロードに変わる手段
2015/5/29 46 Copyright OGIS-RI 2015
template <typename Stream> class packer; template <typename Stream, typename T> packer<Stream>& operator<< (packer<Stream>& o, const T&);
class packer; template <typename T> packer& operator<< (packer& o, const T&); template <> packer& operator<< <int> (packer& o, const int&); http://melpon.org/wandbox/permlink/Jf9HNZaV8IFFE32W
template <typename Stream> packer<Stream>& operator<< <int> (packer<Stream>& o, const int&);
テンプレートの特殊化を使えばinstantiateは遅延される
しかし、関数テンプレートの部分特殊化はできない
もし、packerがクラステンプレートで無ければ、完全特殊化で対応できるのだが
部分特殊化するためには、関数テンプレートではなくクラステンプレートが必要
T を 特殊化した int に置き換えるため、 引数をconst int& にしなければならない
![Page 47: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/47.jpg)
オーバーロードに変わる手段
2015/5/29 47 Copyright OGIS-RI 2015
template <typename Stream, typename T> packer<Stream>& operator<< (packer<Stream>& o, const T&);
template <typename T> struct pack { template <typename Stream> msgpack::packer<Stream>& operator()(msgpack::packer<Stream>&, T const&) const; };
template <typename Stream> packer<Stream>& operator<< (packer<Stream>& o, int);
template <> struct pack<int> { template <typename Stream> msgpack::packer<Stream>& operator()(msgpack::packer<Stream>&, int) const; };
今回のケースでは、クラステンプレートの(完全)特殊化と メンバ関数テンプレートという構成で対応できた
いままでの、関数テンプレートオーバーロードによるAdaptor
クラステンプレートの特殊化によるAdaptor
http://melpon.org/wandbox/permlink/pcJUNyGh7zHMYLmS
![Page 48: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/48.jpg)
オーバーロードに変わる手段
2015/5/29 48 Copyright OGIS-RI 2015
#include <iostream> #include <sstream> namespace msgpack { template <typename Stream> class packer; namespace adaptor { template <typename T> struct pack { template <typename Stream> packer<Stream>& operator()(packer<Stream>& o, const T&) const { std::cout << "Default serialize" << std::endl; return o; } }; } // namespace adaptor template <typename Stream> class packer { public: packer(Stream&) {} template <typename T> packer<Stream>& pack(const T& v) { msgpack::adaptor::pack<T>()(*this, v); return *this; } }; // API template <typename Stream, typename T> inline void pack(Stream& s, const T& v) { packer<Stream>(s).pack(v); } } // namespace msgpack
http://melpon.org/wandbox/permlink/pcJUNyGh7zHMYLmS
// User defined adaptor namespace msgpack { namespace adaptor { template <> struct pack<int> { template <typename Stream> packer<Stream>& operator()(packer<Stream>& o, int) const { std::cout << "Int serialize" << std::endl; return o; } }; } // namespace adaptor } // namespace msgpack int main() { std::stringstream ss; msgpack::pack(ss, 1); msgpack::pack(ss, 1.2); }
![Page 49: Boost sg msgpack](https://reader031.vdocuments.site/reader031/viewer/2022030223/5882df4c1a28ab33258b590b/html5/thumbnails/49.jpg)
まとめ
2015/5/29 49 Copyright OGIS-RI 2015
• ユーザ定義の型などに対して 拡張性を持たせたい場合 関数のオーバーロードよりも クラステンプレートの特殊化の方が柔軟に対応できる – 例:名前空間によるAPIバージョニングとの共存
• 将来が予測できない場合、最も柔軟なメカニズムで 実装しておくと後々苦労しない – msgpack-cは、ライブラリが提供している、 既存の全てのオーバーロードベースのアダプタを クラステンプレートに書き換えた
– 書き換えの際、当然ながら既存のユーザコードへの影響が出た
– msgpack-cではこれを メジャーバージョンアップに伴う破壊的変更とし、 マイグレーションガイドなどのドキュメントも用意した