Poco::DynamicAny を紹介します。
Poco::DynamicAny は、種々の型の値を保持し、型間の変換を透過的に行ってくれます。
意図しないデータロスが無いように、特に数値型どうしの変換時の値の制限や符号変換時に、直感的で妥当な変換が行われるようになっています。
浮動小数点型から整数型への変換や、double から float への変換時は、精度が落ちます。
文字列と char 間の変換で、文字列が1文字以上の時、文字はトランケートされます。空の文字列は ‘\0′ に変換され、空でない文字列は最初の1文字になります。
Boolean 型の変換規則は次のようになります:
・文字列 “false”(大文字小文字とも), “0″, “” は false、それ以外の文字列は true。
・整数の 0 は false、それ以外は true。
・浮動小数点型は、プラットフォームの最小値のとき false、それ以外は true。
POD 型と、もしくは Poco::DynamicAny 間の算術操作は、次の条件付きでサポートされています:
・std::string と const char*:’+', ‘+=’
・整数型と浮動小数点型:’+', ‘+=’, ‘-’, ‘-=’, ‘*’, ‘*=’ , ‘/’, ‘/=’
・整数型:’++’, ‘–’(前置、後置とも)
・それ以外の算術操作では、 Poco::InvalidArgumentException が飛ぶ。
DynamicAnyTest.cpp
・構造体 TestTypes 内の1つの型のデータを設定し、それを他の型に変換。
・CreateTestDynamicAnyInstances<>() というテンプレート関数を再帰的に呼び出し、TestTypes 内の
全ての型に対応。
・eTypeBool と eTypeString について特殊化を定義。
(eTypeString の特殊化関数から eTypeBool の特殊化関数を呼ぶので、 eTypeBool の特殊化を
eTypeString の前に書く必要があることに注意)
#include <Poco/Logger.h> #include <Poco/PatternFormatter.h> #include <Poco/FormattingChannel.h> #include <Poco/ConsoleChannel.h> #include <Poco/DynamicAny.h> #include <Poco/TypeList.h> #include <string> #include <typeinfo> #include <algorithm> #include "ScopedLogMessage.h" enum EMyType { eTypeChar = 0 , eTypeInt8 , eTypeUInt8 , eTypeInt16 , eTypeUInt16 , eTypeInt32 , eTypeUInt32 , eTypeInt64 , eTypeUInt64 , eTypeFloat , eTypeDouble , eTypeString , eTypeBool }; const std::string kMyTypeName[] = { "char" , "Poco::Int8" , "Poco::UInt8" , "Poco::Int16" , "Poco::UInt16" , "Poco::Int32" , "Poco::UInt32" , "Poco::Int64" , "Poco::UInt64" , "float" , "double" , "std::string" , "bool" }; const int kNumMyTypeKind = sizeof(kMyTypeName)/sizeof(kMyTypeName[0]); struct TestTypes { char c; Poco::Int8 i8; Poco::UInt8 u8; Poco::Int16 i16; Poco::UInt16 u16; Poco::Int32 i32; Poco::UInt32 u32; Poco::Int64 i64; Poco::UInt64 u64; float f; double d; std::string s; bool b; }; typedef Poco::TypeListType< char , Poco::Int8 , Poco::UInt8 , Poco::Int16 , Poco::UInt16 , Poco::Int32 , Poco::UInt32 , Poco::Int64 , Poco::UInt64 , float , double , std::string , bool >::HeadType MyTypeList; class TestDynamicAnyBase { public: TestDynamicAnyBase() { } virtual ~TestDynamicAnyBase() { } virtual std::string isNative(const char* typeidStr) = 0; }; template <EMyType N> class TestDynamicAny : public TestDynamicAnyBase { typedef typename Poco::TypeGetter<N, MyTypeList>::HeadType MyType; public: TestDynamicAny(TestTypes& dest, MyType src) : TestDynamicAnyBase() { Poco::DynamicAny a = src; a.convert(dest.i8); a.convert(dest.u8); a.convert(dest.i16); a.convert(dest.u16); a.convert(dest.i32); a.convert(dest.u32); a.convert(dest.i64); a.convert(dest.u64); a.convert(dest.f); a.convert(dest.d); a.convert(dest.b); a.convert(dest.c); a.convert(dest.s); } std::string isNative(const char* typeidStr) { return std::string((std::string(typeid(MyType).name()) == typeidStr) ? "*":" "); } }; template<EMyType N> void CreateTestDynamicAnyInstances(std::vector<TestDynamicAnyBase*>& vec, TestTypes* dest) { typedef typename Poco::TypeGetter<N, MyTypeList>::HeadType MyType; vec[N] = new TestDynamicAny<N>(dest[N], static_cast<MyType>('A'-N)); CreateTestDynamicAnyInstances<static_cast<EMyType>(N+1)>(vec, dest); // recursive call } template<> void CreateTestDynamicAnyInstances<eTypeBool>(std::vector<TestDynamicAnyBase*>& vec, TestTypes* dest) { vec[eTypeBool] = new TestDynamicAny<eTypeBool>(dest[eTypeBool], true); } template<> void CreateTestDynamicAnyInstances<eTypeString>(std::vector<TestDynamicAnyBase*>& vec, TestTypes* dest) { vec[eTypeString] = new TestDynamicAny<eTypeString>(dest[eTypeString], std::string("54")); CreateTestDynamicAnyInstances<static_cast<EMyType>(eTypeString+1)>(vec, dest); // recursive call } class DeleteTestDynamicAnyInstance { public: void operator () (TestDynamicAnyBase* ptr) { delete ptr; } }; void PrepareConsoleLogger(const std::string& name, int level=Poco::Message::PRIO_INFORMATION) { Poco::FormattingChannel* pFCConsole = new Poco::FormattingChannel(new Poco::PatternFormatter("%t")); pFCConsole->setChannel(new Poco::ConsoleChannel); pFCConsole->open(); Poco::Logger::create(name, pFCConsole, level); } int main(int /*argc*/, char** /*argv*/) { PrepareConsoleLogger(Poco::Logger::ROOT, Poco::Message::PRIO_INFORMATION); ScopedLogMessage msg("DynamicAnyTest ", "start", "end"); TestTypes dest[kNumMyTypeKind]; std::vector<TestDynamicAnyBase*> vec(kNumMyTypeKind); CreateTestDynamicAnyInstances<eTypeChar>(vec, &dest[0]); std::string resultStr[kNumMyTypeKind]; for(int i=0; i<kNumMyTypeKind; ++i) { resultStr[eTypeChar] += Poco::format("%3?i%s ", dest[i].c, vec[i]->isNative(typeid(char).name())); resultStr[eTypeInt8] += Poco::format("%3?i%s ", dest[i].i8, vec[i]->isNative(typeid(Poco::Int8).name())); resultStr[eTypeUInt8] += Poco::format("%3?i%s ", dest[i].u8, vec[i]->isNative(typeid(Poco::UInt8).name())); resultStr[eTypeInt16] += Poco::format("%3?i%s ", dest[i].i16, vec[i]->isNative(typeid(Poco::Int16).name())); resultStr[eTypeUInt16] += Poco::format("%3?i%s ", dest[i].u16, vec[i]->isNative(typeid(Poco::UInt16).name())); resultStr[eTypeInt32] += Poco::format("%3?i%s ", dest[i].i32, vec[i]->isNative(typeid(Poco::Int32).name())); resultStr[eTypeUInt32] += Poco::format("%3?i%s ", dest[i].u32, vec[i]->isNative(typeid(Poco::UInt32).name())); resultStr[eTypeInt64] += Poco::format("%3?i%s ", dest[i].i64, vec[i]->isNative(typeid(Poco::Int64).name())); resultStr[eTypeUInt64] += Poco::format("%3?i%s ", dest[i].u64, vec[i]->isNative(typeid(Poco::UInt64).name())); resultStr[eTypeFloat] += Poco::format("%6.2hf%s", dest[i].f, vec[i]->isNative(typeid(float).name())); resultStr[eTypeDouble] += Poco::format("%6.2f%s", dest[i].d, vec[i]->isNative(typeid(double).name())); resultStr[eTypeString] += Poco::format("%4s%s ", Poco::format("\"%s\"", dest[i].s), vec[i]->isNative(typeid(std::string).name())); resultStr[eTypeBool] += Poco::format("%3b%s ", dest[i].b, vec[i]->isNative(typeid(bool).name())); } std::for_each(vec.begin(), vec.end(), DeleteTestDynamicAnyInstance()); for(int i=0; i<kNumMyTypeKind; ++i) { msg.Message(Poco::format("%13s %s", kMyTypeName[i], resultStr[i])); } msg.Message(" " "(NOTE: item with trailing '*' indicates it's the source)"); return 0; }
Results of execution
[0] DynamicAnyTest start [0] char 65* 64 63 62 61 60 59 58 57 56 55 53 1 [0] Poco::Int8 65 64* 63 62 61 60 59 58 57 56 55 54 1 [0] Poco::UInt8 65 64 63* 62 61 60 59 58 57 56 55 54 1 [0] Poco::Int16 65 64 63 62* 61 60 59 58 57 56 55 54 1 [0] Poco::UInt16 65 64 63 62 61* 60 59 58 57 56 55 54 1 [0] Poco::Int32 65 64 63 62 61 60* 59 58 57 56 55 54 1 [0] Poco::UInt32 65 64 63 62 61 60 59* 58 57 56 55 54 1 [0] Poco::Int64 65 64 63 62 61 60 59 58* 57 56 55 54 1 [0] Poco::UInt64 65 64 63 62 61 60 59 58 57* 56 55 54 1 [0] float 65.00 64.00 63.00 62.00 61.00 60.00 59.00 58.00 57.00 56.00* 55.00 54.00 1.00 [0] double 65.00 64.00 63.00 62.00 61.00 60.00 59.00 58.00 57.00 56.00 55.00* 54.00 1.00 [0] std::string "A" "64" "63" "62" "61" "60" "59" "58" "57" "56" "55" "54"* "true" [0] bool 1 1 1 1 1 1 1 1 1 1 1 1 1* [0] (NOTE: item with trailing '*' indicates it's the source) [0] DynamicAnyTest end
Downloads
・ここをクリックすると、makefile や VC++ プロジェクトなど一式がダウンロードできます。
・2010年6月21日からのダウンロード数:177
Subversion
・フリーの Subversion ホスティングサービス Assemblaで、ソースコードを管理しています。
Reference
・http://pocoproject.org にある Types のプレセンテーション。(PDF)
| Copyright © 2010 Round Square Inc. All rights reserved. |
|---|