C++で型情報を持ったままにしておく
やりたいこと
型情報なしに管理したいがないと削除時に困る。削除時だけは型情報が欲しい。
コード
#include <iostream> using namespace std; class Foo { public: Foo() { cout << "Foo" << endl; } virtual ~Foo() { cout << "~Foo" << endl; } protected: void *m_data; }; template<typename T> class Bar : public Foo { public: Bar() { cout << "Bar" << endl; m_data= new T; } virtual ~Bar() { delete reinterpret_cast<T*>(m_data); m_data = nullptr; cout << "~Bar" << endl; } }; class Member { public: Member() { cout << "Member" << endl; } ~Member() { cout << "~Member" << endl; } }; int main() { Bar<Member> bar; }
出力結果
Foo Member Bar ~Member ~Bar ~Foo
呼び出し順も想定通りなのでこれでいいはず。
日本酒会201606その1
最近サボっていた定例会日本酒会を久々に開催。過去の会もそのうちまとめたいところ。
江戸川橋!初めて来た。よく探すなぁと予約してくれた人には感謝。
見たことある寿司が一つも出てこなかったぞ。酢飯屋
本日のメイン、予約してもらったお店は酢飯屋です。超美味しかった。
酢飯屋ではこんなお酒をいただきました
飲んだことがないお酒ばかりですごく楽しかったです。3人で1合ずつもらったので結構種類も飲め満足です。振り返ると九州のお酒が多く、そもそも都内で見かけないものばかりのような気がします(観測範囲)。九州だと、天吹ぐらいしかすぐに出てこないです。
1つ目はたまゆら。長野県、橘倉(きつくら)という酒蔵のお酒です。スパークリング日本酒で日本酒苦手な人でも飲めそうなお酒です。
福岡、山口酒造。庭のうぐいす。
神奈川、泉橋酒造。黒蜻蛉。トンボのマークがかわいい。
夏やごっていうまた虫のラベルのお酒もあって虫が好きなのでしょうか・・・。 夏ヤゴ13 発売 | 泉橋酒造株式会社 Izumibashi SAKE Brewery.
熊本、花の香酒造。
熊本、墨守。瑞鷹という酒蔵。
知らなかったですが造語ではなく存在する言葉のようで
自己の習慣や主張などを、かたく守って変えないこと。 だそうです。 墨守(ボクシュ)とは - コトバンク
料理はどれも見かけないものばかりでした
どれも美味しいし、話も面白いしいい体験だった。
最初はめかぶ。料理はそれぞれ解説があったのですがすぐにメモしてなかったのでところどころわからないものがあって残念です。
載っていたのは、からし菜の種の酢漬けだったはず。硬いので少しつけておいて柔らかくしているのとのこと。魚は石鯛
魚の名前が思い出せなかったですが、2文字ぐらいだったような
タカエビ。甘エビみたいにすごく甘かった記憶が。
名前が思い出せない貝の貝柱。すごいでかいですね。白たまりのみりん漬け。もともと真珠を取る貝で、地元でしか食べられていないものという説明でした。
白たまりは、昔白醤油と呼ばれてたものらしく大豆ではなく小麦粉が多く入っているものだそうです。 使ったことがないので単体でどういう味だか、今度試してみたい。 日東醸造(愛知県碧南市) - 職人醤油
トビウオだったか、キビナゴだったかちょっと記憶が怪しいです。おからを巻いてあるものと外に置かれているのは別の魚と記憶しています。寿司の成り立ちとこの寿司について説明をしてくれて非常に勉強になります。
酢飯屋のページに詳しい事書いてありましたね。 キビナゴのおから寿司 / 郷土寿司プロジェクト / 酢飯屋 - 文京区水道、江戸川橋にある寿司、カフェ、ギャラリーの複合店
古代米と金目鯛。銚子で一本釣りをしたもので傷のない綺麗なものだそうです。傷の有無が魚の値段に大きく影響するらしくなかなかの高級魚だとか。30秒ぐらい噛むようにとの指示。噛めば噛むほど味が出る。
うー、マンボウ!マンボウのホルモンとサワラ。魚じゃなくて肉、ってかなんだこれは!と衝撃を受けた。比較的、ホルモンは日持ちするらしくどうにか食べれるそうです。
もずく寿司。すごいつるつるで麺のよう。
千歳ちゃん。一頭一頭名前をつけて出荷しているこだわりの強い牧場の牛を一頭買いして寿司にしているらしい。
かんぴょう巻きと、納豆巻き。すごいスペックの海苔で巻かれた寿司。海苔の世界でトップクラスとのこと。
穴子が2巻出ました。塩ゆず、山椒の葉。どちらも美味でした。今日一の予感!
デザートにどら焼きと、羊羹をいただきました。(どこのやつだったか説明してもらったけど覚えてない・・・)
料理もお皿も、かかっている絵も何でも知ってるすごい店員さんだったな。
飯田橋を散歩しながら二軒目を見つけたけど、また今度まとめよう。
CollectionViewを使おうと思ってSwiftでCocoaBindingを使ってみた
XCode Version 7.1.1 (7B1005) Swift2.1で試しました。
iOSのアプリは書いたことがあったけど、OSXのアプリは書いたことがなくて色々ハマっている。 iOSだったらUIXXってクラスを使ってGUIを構築してたけど、OSXだとNSXXってクラスを使っていくようだ。
iOSにはなかった気がするけど、CocoaBindingという機能があるらしい。かなり前からあるみたいだけど、普段はWPFでMVVMなコードを書いているのでVM的なものが簡単に実装できるのですごく便利そうだ。
ちなみにAppleのドキュメントはこちら developer.apple.com
下のリンクを参考にしながら、コピペでコードを書いてたところ少しハマったのでまとめておく qiita.com
ビルドが通らなくなる
Storyboard上でCollectionViewを追加したところ
Unknown segue relationship : Prototype
というようなエラーが出てビルドが通らなくなってしまった。
答えはこちら。 stackoverflow.com
追加したタイミングで、CollectionViewからCollectionViewItemへのsegueが登録されていた。これが犯人らしく、一度CollectionViewItemを削除して、CollectionViewItemを追加したらビルドが通った。 stackoverflowの通り手動でItemViewの関連づけをしてやる必要がある
実行時にエラーが出た
[73280:1183774] *** NSForwarding: warning: object 0x6080000454f0 of class 'Foo.Bar' does not implement methodSignatureForSelector: -- trouble ahead Unrecognized selector -[Foo.Bar addObserver:forKeyPath:options:context:]
のようなエラーが出た。バインド元になっている自分で定義したクラスにインターフェイスがないとのこと。NSObjectを継承させることでうまくいった。
iOSと同じつもりでコードを書いてるとちょこちょこハマってしまうのが辛い・・・
AppDelegateでStoryboardからNSWindowControllerを取得してウィンドウを表示するだけでハマった
XCode Version 7.1.1 (7B1005) Swift2.1で試しました。
かなりはまってしまったが、答えはここにあった。表示したいウィンドウのNSWindowControllerをメンバ変数等で拘束しておかないと正しく動作しなかった。 stackoverflow.com
最小コードにすると以下のようにshowWindowするときにインスタンス化されたコントローラーを束縛しておかないといけない。myControllerへの代入コードを除去すると表示されなくなってしまう。
var myController:NSWindowController? = nil func applicationDidFinishLaunching(aNotification: NSNotification) { let controller = mainStoryboard.instantiateInitialController() as? NSWindowController myController = controller myController?.showWindow(nil) }
CFArrayはArrayと等価じゃなかった
XCode Version 7.1.1 (7B1005) Swift2.1で試しました。
CGWindowListCreateDescriptionFromArrayに[Int]を渡したところコンパイルが通ったのでCFArrayとArrayが等価だと思ってていたが使い方が間違っていたようなのでメモ
let windowArray = [1310] let windowsdescription:CFArrayRef = CGWindowListCreateDescriptionFromArray(windowArray)!; let windowInfos = windowsdescription as NSArray? as? [[String: AnyObject]] print(windowInfos?.description)
1310のWindowがあるときに上のようなコードだと、windowInfosが空っぽになってしまう。
let windowIds = [1310] let windowArray = CFArrayCreate ( nil, UnsafeMutablePointer<UnsafePointer<Void>>(windowIds), windowIds.count,nil) let windowsdescription = CGWindowListCreateDescriptionFromArray(windowArray)!; let windowInfos = windowsdescription as NSArray? as? [[String: AnyObject]] print(windowInfos?.description)
のようにCFArrayを作ってから関数を呼ぶようにすると無事適切な値が帰ってくるようになった。 それっぽくコンパイルが通っても意図通りになっていないケースがあるのでObjectiveCの関数を呼ぶ時は注意が必要そうだ。
GraphQLのサンプルに書き加えてみた
できたこと
独自のItemというデータ構造を追加してそれを作成・取得することができるようになった。
データ定義をしておくとバリテーションをしてくれることがわかった。 クライアント側で欲しいフィールドを調整したい場合は便利そうな気がした。
独自実装を追加していく
前回起動まで成功した https://github.com/RisingStack/graphql-serverをローカルにクローンしてきてこのクライアントとサーバーをいじっていきます。
Nodejs+MongoDBという環境で実装されていて、今回は
- mongoose(MongoDBライブラリ)のモデルクラスの定義
- GraphQLのスキーマを定義
- クライアント側コードを記述。作成と取得クエリを投げるようにする
という手順で作業を進めます。
mongoose(MongoDBライブラリ)のモデルクラスの定義
src/server/user.jsがmongooseのモデルクラスの定義なので、これをコピペしてsrc/server/item.jsを作ります。以下のようなコードになりました。
import mongoose from 'mongoose'; var ItemSchema = new mongoose.Schema({ name: { type: String } }); var Item = mongoose.model('Item', ItemSchema); export default Item;
GraphQLのスキーマを定義
src/server/schema.jsを編集していきます。
import Item from './item';
を追加して先ほど書いたitem.jsを読み込みます。
GraphQLスキーマ向けにモデル定義をします。mongooseの方でもしてるので一緒にできると良いなと思います。
var itemType = new GraphQLObjectType({ name: 'Item', description: 'Item creator', fields: () => ({ id: { type: new GraphQLNonNull(GraphQLString), description: 'The id of the item.', }, name: { type: GraphQLString, description: 'The name of the item.', }, }) });
GraphQLSchemaのqueryには取得クエリ、mutationには作成・更新・削除などの変更を加えるクエリを実装します。 詳しくは仕様を読むと良いです。
取得クエリ(getItem)を定義
query: new GraphQLObjectType({ name: 'RootQueryType', fields: { getItem: { type: itemType, args: { name: { name: 'name', type: new GraphQLNonNull(GraphQLString) } }, resolve: (root, {name}, source, fieldASTs) => { return Item.findOne({name: name}); } }, } }
次に作成クエリ(createItem)を定義します。
mutation: new GraphQLObjectType({ name: 'Mutation', fields: { createItem: { type: itemType, args: { name: { name: 'name', type: GraphQLString } }, resolve: (obj, {name}, source, fieldASTs) => co(function *() { var item = new Item(); item.name = name; return yield item.save(); }) }, } }),
最終的にsrc/server/schema.jsは以下のようになりました。
import { GraphQLObjectType, GraphQLNonNull, GraphQLSchema, GraphQLString, GraphQLList } from 'graphql/type'; import co from 'co'; import User from './user'; import Item from './item'; /** * generate projection object for mongoose * @param {Object} fieldASTs * @return {Project} */ function getProjection (fieldASTs) { return fieldASTs.selectionSet.selections.reduce((projections, selection) => { projections[selection.name.value] = 1; return projections; }, {}); } var userType = new GraphQLObjectType({ name: 'User', description: 'User creator', fields: () => ({ id: { type: new GraphQLNonNull(GraphQLString), description: 'The id of the user.', }, name: { type: GraphQLString, description: 'The name of the user.', }, friends: { type: new GraphQLList(userType), description: 'The friends of the user, or an empty list if they have none.', resolve: (user, params, source, fieldASTs) => { var projections = getProjection(fieldASTs); return User.find({ _id: { // to make it easily testable $in: user.friends.map((id) => id.toString()) } }, projections); }, } }) }); var itemType = new GraphQLObjectType({ name: 'Item', description: 'Item creator', fields: () => ({ id: { type: new GraphQLNonNull(GraphQLString), description: 'The id of the item.', }, name: { type: GraphQLString, description: 'The name of the item.', }, }) }); var schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'RootQueryType', fields: { hello: { type: GraphQLString, resolve: function() { return 'world'; } }, user: { type: userType, args: { id: { name: 'id', type: new GraphQLNonNull(GraphQLString) } }, resolve: (root, {id}, source, fieldASTs) => { var projections = getProjection(fieldASTs); return User.findById(id, projections); } }, getItem: { type: itemType, args: { name: { name: 'name', type: new GraphQLNonNull(GraphQLString) } }, resolve: (root, {name}, source, fieldASTs) => { return Item.findOne({name: name}); } }, } }), // mutation mutation: new GraphQLObjectType({ name: 'Mutation', fields: { createUser: { type: userType, args: { name: { name: 'name', type: GraphQLString } }, resolve: (obj, {name}, source, fieldASTs) => co(function *() { var projections = getProjection(fieldASTs); var user = new User(); user.name = name; return yield user.save(); }) }, deleteUser: { type: userType, args: { id: { name: 'id', type: new GraphQLNonNull(GraphQLString) } }, resolve: (obj, {id}, source, fieldASTs) => co(function *() { var projections = getProjection(fieldASTs); console.log(id); return yield User.findOneAndRemove({_id: id}); }) }, updateUser: { type: userType, args: { id: { name: 'id', type: new GraphQLNonNull(GraphQLString) }, name: { name: 'name', type: GraphQLString } }, resolve: (obj, {id, name}, source, fieldASTs) => co(function *() { var projections = getProjection(fieldASTs); yield User.update({ _id: id }, { $set: { name: name } }); return yield User.findById(id, projections); }) }, createItem: { type: itemType, args: { name: { name: 'name', type: GraphQLString } }, resolve: (obj, {name}, source, fieldASTs) => co(function *() { var projections = getProjection(fieldASTs); var item = new Item(); item.name = name; return yield item.save(); }) }, } }), }); export var getProjection; export default schema;
クライアント側コードを記述。作成と取得クエリを投げるようにする
作成クエリを投げるコードを書くのでsrc/client/mutation.jsを編集します。
Itemデータを作成するために先ほど実装したcreateItemを使います。hogehogehogeというItemを作成します。
var itemName = 'hogehogehoge' request .post('http://localhost:3000/data') .send({ query: ` mutation M($name: String!) { createItem(name: $name) { name } } `, params: { name: itemName } }) .end(function (err, res) { debug(err || res.body); debug('created', res.body); });
src/client/mutation.jsは以下のようになりました。最初からあったコードはデバッグの都合で除去しました。
import request from 'superagent'; import Debug from 'debug'; var debug = new Debug('client:mutation'); var itemName = 'hogehogehoge' request .post('http://localhost:3000/data') .send({ query: ` mutation M($name: String!) { createItem(name: $name) { name } } `, params: { name: itemName } }) .end(function (err, res) { debug(err || res.body); debug('created', res.body); });
取得クエリを投げるコードを書きます。src/client/query.jsを以下のようなコードを追加します。 (var name = 'hogehogehoge'としていたらうまく動かなかったです。変数名とフィールド名がぶつかるとまずい?)
var itemName = 'hogehogehoge' request .get('http://localhost:3000/data') .query({ query: `{ getItem(name: "${itemName}") { name } }` }) .end(function (err, res) { debug('items', res.body); });
ということで、src/client/query.jsは以下のようになりました。最初からあったコードはデバッグの都合で除去しました。
import request from 'superagent'; import Debug from 'debug'; var debug = new Debug('client:query'); var itemName = 'hogehogehoge' request .get('http://localhost:3000/data') .query({ query: `{ getItem(name: "${itemName}") { name } }` }) .end(function (err, res) { debug('items', res.body); });
上記のようにコードを編集していったら、前回同様に
npm start
としてサーバーを起動して、別のscreenで
npm run client
とクライアントを起動すると、無事データの作成と取得が確認できます。
GraphQLサーバー起動まで試した
Facebookの発表したGraphQLが気になったのでインストールまでやってみました。
qiitaではまだ記事が全然上がっていない模様。
ここにすでにサーバーの実装がいたので試すのは簡単そう。
RisingStack/graphql-server · GitHub
インストールの説明に手順が書いてあるので問題ないのですが以下のような手順でやりました。 環境はUbuntu 14.04です。
sudo apt-get install mongodb git clone https://github.com/RisingStack/graphql-server.git ~/graphql-server cd ~/graphql-server npm install npm run seed npm start
これでサーバーが起動します。mongodbが起動していないと、"npm run seed"のところで
Error: connect ECONNREFUSED at exports._errnoException (util.js:746:11) at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1010:19)
こんなエラーが出てしまうので注意。
無事サーバーが起動したところで、別のコンソールで
npm run client
とクライアントを起動すると何か出力が出て起動を確認できました。めでたしめでたし
次はもう少し弄ってみる予定。