SlideShare una empresa de Scribd logo
1 de 49
Descargar para leer sin conexión
MessagePackとAPIバージョニング
近藤 貴俊
2015/5/29 1Copyright OGIS-RI 2015
• 近藤貴俊
• 株式会社オージス総研
– IoT分野でMessagePackを利用した
データの収集、制御を行う
プラットフォームを開発している
• msgpack-c コミッタの一人
– 後述するMessagePackフォーマットを扱うための
C/C++ 実装
– C++版は
Cのwrapperではない
• C++Nowに
ここ6年くらい
連続参加中
2015/5/29 Copyright OGIS-RI 2015 2
自己紹介
2015/5/29 Copyright OGIS-RI 2015 3
MessagePackとは
2015/5/29 Copyright OGIS-RI 2015 4
MessagePackとは
2015/5/29 Copyright OGIS-RI 2015 5
MessagePackとは
2015/5/29 Copyright OGIS-RI 2015 6
MessagePackとは
2015/5/29 Copyright OGIS-RI 2015 7
MessagePackとは
2015/5/29 Copyright OGIS-RI 2015 8
MessagePackとは
2015/5/29 Copyright OGIS-RI 2015 9
MessagePackとは
https://github.com/msgpack/msgpack/blob/master/spec.md
• Website http://msgpack.org/
• JSONと同様
– ポータブル
– 基本的な型情報を内包
– コンポジットなデータ構造(詳細は次ページで)
• JSONとの違い
– サイズが小さい
– バイナリフォーマット
– バイナリデータもそのまま扱える
– 整数と浮動小数点数を区別
– Parseが容易で計算負荷が小さい
2015/5/29 Copyright OGIS-RI 2015 10
MessagePackとは?
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 の名称で記載
MessagePackをサポートする言語
2015/5/29 Copyright OGIS-RI 2015 12
MessagePackをサポートする言語
2015/5/29 Copyright OGIS-RI 2015 13
このリストは github から自動収集して生成されているため
どのレベルで実装されているかは要確認
2015/5/29 Copyright OGIS-RI 2015 14
msgpack-c
中でも、C++にフォーカスをあてた内容で、
Cには当てはまらない内容もあるので注意
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
C++/object/byte stream
2015/5/29 16Copyright OGIS-RI 2015
C++ Types
msgpack::object
Byte stream
pack object
pack unpack
convert
adaptor
Adaptor
2015/5/29 17Copyright 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
自前のクラスのmsgpack対応
2015/5/29 18Copyright 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
自前のクラスのmsgpack対応
2015/5/29 19Copyright 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
ADLを用いたアダプタの実現
2015/5/29 20Copyright 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
まで
ADLを用いたアダプタの実現
2015/5/29 21Copyright 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<<オーバーロード
APIのバージョニング
2015/5/29 22Copyright OGIS-RI 2015
• msgpack-c の C++版はヘッダオンリーライブラリとなった
• ヘッダオンリーライブラリであっても、古いABIのmsgpack-c
をincludeして作ったライブラリ(.a , .LIBなど)を、
新しいABIのmsgpack-cと合わせて使うと問題が生じる
– std::listのサイズをO(1)で求めることになった際にも
同様の問題が発生した
• これを防ぐために、ABIに変更が生じた場合、
古いバージョンはそのまま使い続けられるようにしたい
• ABIに関わらないバグフィックスなどは
古いバージョンにも反映していきたい
msgpack.hpp
userlib.cpplibuser.a
msgpack.hpp
client.cpp
include
生成
include
link
APIのバージョニング
2015/5/29 23Copyright 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
APIのバージョニング
2015/5/29 24Copyright 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()
APIのバージョニング
2015/5/29 25Copyright 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を上手く使い分けることでバージョニングを実現
APIのバージョニング
2015/5/29 26Copyright OGIS-RI 2015
A
B
C
msgpack::B()
msgpack::C()
V1
D
msgpack::D()
inline namespace
APIのバージョニング
2015/5/29 27Copyright 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
using v1::B
using V1::C
using v1::D
APIのバージョニング
2015/5/29 28Copyright 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
using v1::B
using V1::C
using v1::D
APIのバージョニング
2015/5/29 29Copyright 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
using v1::B
using V1::C
using v1::D
APIのバージョニング
2015/5/29 30Copyright 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変更対応
using v1::B
using V1::C
using v1::D
APIのバージョニング
2015/5/29 31Copyright 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
using v1::B
using V1::C
using v1::D
APIのバージョニング
2015/5/29 32Copyright 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変更対応
using v1::B
using V1::C
using v1::D
APIのバージョニング
2015/5/29 33Copyright 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変更対応
をここでは行わない
using v1::B
using V1::C
using v1::D
APIのバージョニング
2015/5/29 34Copyright OGIS-RI 2015
A
B''
C
A
C
ABI変更
msgpack::B()
V1 V2 V3
D
msgpack::D()
Bmsgpack::B()
inline namespace
msgpack::v1::C()
msgpack::D()
msgpack::C()
using v2::D
CのABI変更対応
ABI変更
using v1::B
using V1::C
using v1::D
APIのバージョニング
2015/5/29 35Copyright 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変更
using v1::B
using V1::C
using v1::D
APIのバージョニング
2015/5/29 36Copyright 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変更対応
using v1::B
using V1::C
using v1::D
APIのバージョニング
2015/5/29 37Copyright 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
using v1::B
using V1::C
using v1::D
APIのバージョニング
2015/5/29 38Copyright 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に変更がある場合
ADL問題
2015/5/29 39Copyright 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は
参照されない
ADL問題
2015/5/29 40Copyright 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'
ADL問題
2015/5/29 41Copyright 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
先行宣言を入れてみると。。。
ADL問題
2015/5/29 42Copyright 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);
}
ユーザ定義のオーバーロードが呼ばれない
ADL問題
2015/5/29 43Copyright 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);
}
ユーザ定義のオーバーロードの先行宣言を入れると
期待通りディスパッチされる
ADL問題
2015/5/29 44Copyright OGIS-RI 2015
msgpackの先行宣言群
ユーザの先行宣言群
msgpackのライブラリ本体
ユーザのコード本体
#include <msgpack_fwd.hpp>
#include <msgpack.hpp>
user.cpp
このアプローチの行き着く先にあるもの
ユーザコードの書き方に大きな制約を課してしまう
なにが問題なのか?
2015/5/29 45Copyright OGIS-RI 2015
• オーバーロードによるアダプタの実現
– オーバーロードは、呼び出しコードがinstantiateした際、
そこから見えている関数が候補となる
– ADLによって、呼び出しコードのinstantiate を遅延
– ADLを使うためには、名前空間修飾してはならない
• APIバージョニングの実現
– 名前空間修飾しないとAPIバージョニングできない
• この2つの相性が悪い
オーバーロードに変わる手段
2015/5/29 46Copyright 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& にしなければならない
オーバーロードに変わる手段
2015/5/29 47Copyright 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
オーバーロードに変わる手段
2015/5/29 48Copyright 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);
}
まとめ
2015/5/29 49Copyright OGIS-RI 2015
• ユーザ定義の型などに対して
拡張性を持たせたい場合
関数のオーバーロードよりも
クラステンプレートの特殊化の方が柔軟に対応できる
– 例:名前空間によるAPIバージョニングとの共存
• 将来が予測できない場合、最も柔軟なメカニズムで
実装しておくと後々苦労しない
– msgpack-cは、ライブラリが提供している、
既存の全てのオーバーロードベースのアダプタを
クラステンプレートに書き換えた
– 書き換えの際、当然ながら既存のユーザコードへの影響が出た
– msgpack-cではこれを
メジャーバージョンアップに伴う破壊的変更とし、
マイグレーションガイドなどのドキュメントも用意した

Más contenido relacionado

La actualidad más candente

Stream processing and Norikra
Stream processing and NorikraStream processing and Norikra
Stream processing and Norikra
SATOSHI TAGOMORI
 

La actualidad más candente (20)

Rust-DPDK
Rust-DPDKRust-DPDK
Rust-DPDK
 
Reactive Extensionsで非同期処理を簡単に
Reactive Extensionsで非同期処理を簡単にReactive Extensionsで非同期処理を簡単に
Reactive Extensionsで非同期処理を簡単に
 
NanoStrand
NanoStrandNanoStrand
NanoStrand
 
Rubyで実はwritev(2) が使われているはなし
Rubyで実はwritev(2) が使われているはなしRubyで実はwritev(2) が使われているはなし
Rubyで実はwritev(2) が使われているはなし
 
Rust-DPDK
Rust-DPDKRust-DPDK
Rust-DPDK
 
HTTP/2, QUIC入門
HTTP/2, QUIC入門HTTP/2, QUIC入門
HTTP/2, QUIC入門
 
WebRTC multitrack / multistream
WebRTC multitrack / multistreamWebRTC multitrack / multistream
WebRTC multitrack / multistream
 
qmake入門
qmake入門qmake入門
qmake入門
 
WebRTC meetup Tokyo 1
WebRTC meetup  Tokyo 1WebRTC meetup  Tokyo 1
WebRTC meetup Tokyo 1
 
Stream processing and Norikra
Stream processing and NorikraStream processing and Norikra
Stream processing and Norikra
 
Node.js with WebRTC DataChannel
Node.js with WebRTC DataChannelNode.js with WebRTC DataChannel
Node.js with WebRTC DataChannel
 
JSONでメール送信 | HTTP API Server ``Haineko''/YAPC::Asia Tokyo 2013 LT Day2
JSONでメール送信 | HTTP API Server ``Haineko''/YAPC::Asia Tokyo 2013 LT Day2JSONでメール送信 | HTTP API Server ``Haineko''/YAPC::Asia Tokyo 2013 LT Day2
JSONでメール送信 | HTTP API Server ``Haineko''/YAPC::Asia Tokyo 2013 LT Day2
 
MPSoCのPLの性能について
MPSoCのPLの性能についてMPSoCのPLの性能について
MPSoCのPLの性能について
 
WebRTC UserMedia Catalog: いろんなユーザメディア(MediaStream)を使ってみよう
WebRTC UserMedia Catalog: いろんなユーザメディア(MediaStream)を使ってみようWebRTC UserMedia Catalog: いろんなユーザメディア(MediaStream)を使ってみよう
WebRTC UserMedia Catalog: いろんなユーザメディア(MediaStream)を使ってみよう
 
Googleの基盤クローン Hadoopについて
Googleの基盤クローン HadoopについてGoogleの基盤クローン Hadoopについて
Googleの基盤クローン Hadoopについて
 
C#次世代非同期処理概観 - Task vs Reactive Extensions
C#次世代非同期処理概観 - Task vs Reactive ExtensionsC#次世代非同期処理概観 - Task vs Reactive Extensions
C#次世代非同期処理概観 - Task vs Reactive Extensions
 
Rake
RakeRake
Rake
 
Gocon2017:Goのロギング周りの考察
Gocon2017:Goのロギング周りの考察Gocon2017:Goのロギング周りの考察
Gocon2017:Goのロギング周りの考察
 
Gpgpu tomoaki-fp16
Gpgpu tomoaki-fp16Gpgpu tomoaki-fp16
Gpgpu tomoaki-fp16
 
Ietf97 ソウル報告
Ietf97 ソウル報告Ietf97 ソウル報告
Ietf97 ソウル報告
 

Destacado (6)

C++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるC++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISる
 
C++14 solve explicit_default_constructor
C++14 solve explicit_default_constructorC++14 solve explicit_default_constructor
C++14 solve explicit_default_constructor
 
Glfw3,OpenGL,GUI
Glfw3,OpenGL,GUI Glfw3,OpenGL,GUI
Glfw3,OpenGL,GUI
 
C++14 enum hash
C++14 enum hashC++14 enum hash
C++14 enum hash
 
Boost.Timer
Boost.TimerBoost.Timer
Boost.Timer
 
Introduction to boost test
Introduction to boost testIntroduction to boost test
Introduction to boost test
 

Similar a Boost sg msgpack

SDN Lab環境でのRobotFramework実践活用
SDN Lab環境でのRobotFramework実践活用SDN Lab環境でのRobotFramework実践活用
SDN Lab環境でのRobotFramework実践活用
Toshiki Tsuboi
 
ネットワークコマンド入力に対応したツール事例
ネットワークコマンド入力に対応したツール事例ネットワークコマンド入力に対応したツール事例
ネットワークコマンド入力に対応したツール事例
fumoto kazuhiro
 

Similar a Boost sg msgpack (20)

20130315 abc firefox_os
20130315 abc firefox_os20130315 abc firefox_os
20130315 abc firefox_os
 
Let's begin WebRTC
Let's begin WebRTCLet's begin WebRTC
Let's begin WebRTC
 
Server side Swift & Photo Booth
Server side Swift & Photo Booth Server side Swift & Photo Booth
Server side Swift & Photo Booth
 
ABEMA を次のフェーズへ進化させる技術への取り組み
ABEMA を次のフェーズへ進化させる技術への取り組みABEMA を次のフェーズへ進化させる技術への取り組み
ABEMA を次のフェーズへ進化させる技術への取り組み
 
Telemetryについて
TelemetryについてTelemetryについて
Telemetryについて
 
sveltekit-ja.pdf
sveltekit-ja.pdfsveltekit-ja.pdf
sveltekit-ja.pdf
 
Microsoft Graph API Library for Go
Microsoft Graph API Library for GoMicrosoft Graph API Library for Go
Microsoft Graph API Library for Go
 
Prometheus超基礎公開用.pdf
Prometheus超基礎公開用.pdfPrometheus超基礎公開用.pdf
Prometheus超基礎公開用.pdf
 
SDN Lab環境でのRobotFramework実践活用
SDN Lab環境でのRobotFramework実践活用SDN Lab環境でのRobotFramework実践活用
SDN Lab環境でのRobotFramework実践活用
 
ネットワークコマンド入力に対応したツール事例
ネットワークコマンド入力に対応したツール事例ネットワークコマンド入力に対応したツール事例
ネットワークコマンド入力に対応したツール事例
 
How to run P4 BMv2
How to run P4 BMv2How to run P4 BMv2
How to run P4 BMv2
 
Docker ComposeでMastodonが必要なものを梱包する話
Docker ComposeでMastodonが必要なものを梱包する話Docker ComposeでMastodonが必要なものを梱包する話
Docker ComposeでMastodonが必要なものを梱包する話
 
Rancher2.3とwindows Containerで作るkubernetesクラスタ
Rancher2.3とwindows Containerで作るkubernetesクラスタRancher2.3とwindows Containerで作るkubernetesクラスタ
Rancher2.3とwindows Containerで作るkubernetesクラスタ
 
WebRTC開発者向けプラットフォーム SkyWayの裏側
WebRTC開発者向けプラットフォーム SkyWayの裏側WebRTC開発者向けプラットフォーム SkyWayの裏側
WebRTC開発者向けプラットフォーム SkyWayの裏側
 
memcached proxy server development and operation
memcached proxy server development and operationmemcached proxy server development and operation
memcached proxy server development and operation
 
Testing and packaging WebRTC Stack
Testing and packaging WebRTC StackTesting and packaging WebRTC Stack
Testing and packaging WebRTC Stack
 
Ansible2.0と実用例
Ansible2.0と実用例Ansible2.0と実用例
Ansible2.0と実用例
 
Firefox5+HTML5×5
Firefox5+HTML5×5Firefox5+HTML5×5
Firefox5+HTML5×5
 
AnsibleおよびDockerで始めるInfrastructure as a Code
AnsibleおよびDockerで始めるInfrastructure as a CodeAnsibleおよびDockerで始めるInfrastructure as a Code
AnsibleおよびDockerで始めるInfrastructure as a Code
 
The road of Apache CloudStack Contributor (Translation and Patch)
The road of Apache CloudStack Contributor (Translation and Patch)The road of Apache CloudStack Contributor (Translation and Patch)
The road of Apache CloudStack Contributor (Translation and Patch)
 

Más de Takatoshi Kondo

Aho-Corasick string matching algorithm
Aho-Corasick string matching algorithmAho-Corasick string matching algorithm
Aho-Corasick string matching algorithm
Takatoshi Kondo
 

Más de Takatoshi Kondo (9)

Effective Modern C++ study group Item39
Effective Modern C++ study group Item39Effective Modern C++ study group Item39
Effective Modern C++ study group Item39
 
MessagePack(msgpack): Compact and Fast Serialization Library
MessagePack(msgpack): Compact and Fast Serialization LibraryMessagePack(msgpack): Compact and Fast Serialization Library
MessagePack(msgpack): Compact and Fast Serialization Library
 
Emcpp0506
Emcpp0506Emcpp0506
Emcpp0506
 
Boostsapporomsmpost 111106070819-phpapp02
Boostsapporomsmpost 111106070819-phpapp02Boostsapporomsmpost 111106070819-phpapp02
Boostsapporomsmpost 111106070819-phpapp02
 
Boostsapporomsmpre 111030054504-phpapp02
Boostsapporomsmpre 111030054504-phpapp02Boostsapporomsmpre 111030054504-phpapp02
Boostsapporomsmpre 111030054504-phpapp02
 
Unpack mechanism of the msgpack-c
Unpack mechanism of the msgpack-cUnpack mechanism of the msgpack-c
Unpack mechanism of the msgpack-c
 
N3495 inplace realloc
N3495 inplace reallocN3495 inplace realloc
N3495 inplace realloc
 
N3701 concept lite
N3701 concept liteN3701 concept lite
N3701 concept lite
 
Aho-Corasick string matching algorithm
Aho-Corasick string matching algorithmAho-Corasick string matching algorithm
Aho-Corasick string matching algorithm
 

Boost sg msgpack

  • 2. • 近藤貴俊 • 株式会社オージス総研 – IoT分野でMessagePackを利用した データの収集、制御を行う プラットフォームを開発している • msgpack-c コミッタの一人 – 後述するMessagePackフォーマットを扱うための C/C++ 実装 – C++版は Cのwrapperではない • C++Nowに ここ6年くらい 連続参加中 2015/5/29 Copyright OGIS-RI 2015 2 自己紹介
  • 3. 2015/5/29 Copyright OGIS-RI 2015 3 MessagePackとは
  • 4. 2015/5/29 Copyright OGIS-RI 2015 4 MessagePackとは
  • 5. 2015/5/29 Copyright OGIS-RI 2015 5 MessagePackとは
  • 6. 2015/5/29 Copyright OGIS-RI 2015 6 MessagePackとは
  • 7. 2015/5/29 Copyright OGIS-RI 2015 7 MessagePackとは
  • 8. 2015/5/29 Copyright OGIS-RI 2015 8 MessagePackとは
  • 9. 2015/5/29 Copyright OGIS-RI 2015 9 MessagePackとは https://github.com/msgpack/msgpack/blob/master/spec.md
  • 10. • Website http://msgpack.org/ • JSONと同様 – ポータブル – 基本的な型情報を内包 – コンポジットなデータ構造(詳細は次ページで) • JSONとの違い – サイズが小さい – バイナリフォーマット – バイナリデータもそのまま扱える – 整数と浮動小数点数を区別 – Parseが容易で計算負荷が小さい 2015/5/29 Copyright OGIS-RI 2015 10 MessagePackとは?
  • 11. 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 の名称で記載
  • 13. MessagePackをサポートする言語 2015/5/29 Copyright OGIS-RI 2015 13 このリストは github から自動収集して生成されているため どのレベルで実装されているかは要確認
  • 14. 2015/5/29 Copyright OGIS-RI 2015 14 msgpack-c 中でも、C++にフォーカスをあてた内容で、 Cには当てはまらない内容もあるので注意
  • 15. 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
  • 16. C++/object/byte stream 2015/5/29 16Copyright OGIS-RI 2015 C++ Types msgpack::object Byte stream pack object pack unpack convert adaptor
  • 17. Adaptor 2015/5/29 17Copyright 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
  • 18. 自前のクラスのmsgpack対応 2015/5/29 18Copyright 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
  • 19. 自前のクラスのmsgpack対応 2015/5/29 19Copyright 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
  • 20. ADLを用いたアダプタの実現 2015/5/29 20Copyright 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 まで
  • 21. ADLを用いたアダプタの実現 2015/5/29 21Copyright 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<<オーバーロード
  • 22. APIのバージョニング 2015/5/29 22Copyright OGIS-RI 2015 • msgpack-c の C++版はヘッダオンリーライブラリとなった • ヘッダオンリーライブラリであっても、古いABIのmsgpack-c をincludeして作ったライブラリ(.a , .LIBなど)を、 新しいABIのmsgpack-cと合わせて使うと問題が生じる – std::listのサイズをO(1)で求めることになった際にも 同様の問題が発生した • これを防ぐために、ABIに変更が生じた場合、 古いバージョンはそのまま使い続けられるようにしたい • ABIに関わらないバグフィックスなどは 古いバージョンにも反映していきたい msgpack.hpp userlib.cpplibuser.a msgpack.hpp client.cpp include 生成 include link
  • 23. APIのバージョニング 2015/5/29 23Copyright 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
  • 24. APIのバージョニング 2015/5/29 24Copyright 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()
  • 25. APIのバージョニング 2015/5/29 25Copyright 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を上手く使い分けることでバージョニングを実現
  • 26. APIのバージョニング 2015/5/29 26Copyright OGIS-RI 2015 A B C msgpack::B() msgpack::C() V1 D msgpack::D() inline namespace
  • 27. APIのバージョニング 2015/5/29 27Copyright 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
  • 28. using v1::B using V1::C using v1::D APIのバージョニング 2015/5/29 28Copyright 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
  • 29. using v1::B using V1::C using v1::D APIのバージョニング 2015/5/29 29Copyright 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
  • 30. using v1::B using V1::C using v1::D APIのバージョニング 2015/5/29 30Copyright 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変更対応
  • 31. using v1::B using V1::C using v1::D APIのバージョニング 2015/5/29 31Copyright 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
  • 32. using v1::B using V1::C using v1::D APIのバージョニング 2015/5/29 32Copyright 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変更対応
  • 33. using v1::B using V1::C using v1::D APIのバージョニング 2015/5/29 33Copyright 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変更対応 をここでは行わない
  • 34. using v1::B using V1::C using v1::D APIのバージョニング 2015/5/29 34Copyright OGIS-RI 2015 A B'' C A C ABI変更 msgpack::B() V1 V2 V3 D msgpack::D() Bmsgpack::B() inline namespace msgpack::v1::C() msgpack::D() msgpack::C() using v2::D CのABI変更対応 ABI変更
  • 35. using v1::B using V1::C using v1::D APIのバージョニング 2015/5/29 35Copyright 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変更
  • 36. using v1::B using V1::C using v1::D APIのバージョニング 2015/5/29 36Copyright 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変更対応
  • 37. using v1::B using V1::C using v1::D APIのバージョニング 2015/5/29 37Copyright 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
  • 38. using v1::B using V1::C using v1::D APIのバージョニング 2015/5/29 38Copyright 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に変更がある場合
  • 39. ADL問題 2015/5/29 39Copyright 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は 参照されない
  • 40. ADL問題 2015/5/29 40Copyright 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'
  • 41. ADL問題 2015/5/29 41Copyright 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 先行宣言を入れてみると。。。
  • 42. ADL問題 2015/5/29 42Copyright 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); } ユーザ定義のオーバーロードが呼ばれない
  • 43. ADL問題 2015/5/29 43Copyright 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); } ユーザ定義のオーバーロードの先行宣言を入れると 期待通りディスパッチされる
  • 44. ADL問題 2015/5/29 44Copyright OGIS-RI 2015 msgpackの先行宣言群 ユーザの先行宣言群 msgpackのライブラリ本体 ユーザのコード本体 #include <msgpack_fwd.hpp> #include <msgpack.hpp> user.cpp このアプローチの行き着く先にあるもの ユーザコードの書き方に大きな制約を課してしまう
  • 45. なにが問題なのか? 2015/5/29 45Copyright OGIS-RI 2015 • オーバーロードによるアダプタの実現 – オーバーロードは、呼び出しコードがinstantiateした際、 そこから見えている関数が候補となる – ADLによって、呼び出しコードのinstantiate を遅延 – ADLを使うためには、名前空間修飾してはならない • APIバージョニングの実現 – 名前空間修飾しないとAPIバージョニングできない • この2つの相性が悪い
  • 46. オーバーロードに変わる手段 2015/5/29 46Copyright 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& にしなければならない
  • 47. オーバーロードに変わる手段 2015/5/29 47Copyright 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
  • 48. オーバーロードに変わる手段 2015/5/29 48Copyright 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); }
  • 49. まとめ 2015/5/29 49Copyright OGIS-RI 2015 • ユーザ定義の型などに対して 拡張性を持たせたい場合 関数のオーバーロードよりも クラステンプレートの特殊化の方が柔軟に対応できる – 例:名前空間によるAPIバージョニングとの共存 • 将来が予測できない場合、最も柔軟なメカニズムで 実装しておくと後々苦労しない – msgpack-cは、ライブラリが提供している、 既存の全てのオーバーロードベースのアダプタを クラステンプレートに書き換えた – 書き換えの際、当然ながら既存のユーザコードへの影響が出た – msgpack-cではこれを メジャーバージョンアップに伴う破壊的変更とし、 マイグレーションガイドなどのドキュメントも用意した