フェルマータ

個人用のメモ。ソフトウェアの導入とかが多くなる予定。ライセンスの気になる方はこのブログに載せたコードは修正 BSD に準ずるものと考えてください。

Qt の ui ファイルを cmake (CLion)から使う

ポエム

 何度やっても QT_UIC_EXECUTABLE is missing といいよる cmake に愛想を尽かさず頑張った。 Qt の *.ui ファイルを使う方法がわかったので記事を書く。Qt 記事少なすぎでしょみんなもっと記事書いて!英語記事ですらほとんどないじゃん。

症状

 以下の様な CMakeLists を 使うと、 QT_UIC_EXECUTABLE 無いんだけどwwwと cmake が激おこしてた。

# sources
qt_wrap_ui(vsampler_corpus_editor view/ui_CorpusMetaInfoView.h view/ui_CorpusMetaInfoView.cpp vioew/CorpusMetaInfoView.ui)
add_library(vsampler_corpus_editor ${files_you_need})

対処法

 リファレンス見ると一見これで正しそうだしなんとかなりそうだがお前の qt_wrap_ui の使い方は間違っている。 結局ちゃんと設定ができていないのが問題だったらしい。

# sources
qt5_wrap_ui(QT_CORPUS_EDITOR_UI_HEADERS hoge.ui foo.ui)
add_library(vsampler_corpus_editor ${QT_CORPUS_EDITOR_UI_HEADERS} ${files_you_need})

こうしろってさ。んで cpp, c++ ファイルからこうせよってさ。

#include "ui_Hoge.h"
#include "Hoge.h"

hoge::Hoge(QWidget *parent)
        : QMainWindow(parent), ui(new Ui::Hoge) {
    ui->setupUi(this);
}

hoge::Hoge::~Hoge() {
    delete ui;
}

cpp ファイルの方は Qt Creator に準じているだけ。これで *.ui のヘッダファイルが生成されていい感じになる。 一週間かかった死にたい。

Qt を cmake から使う(CLion から使う)。

概要

 Qt の開発というととりあえず QtCreator を使えばいいだろ、と思うのだが、最近 JetBrains から CLion という神ツールが発売された。

www.jetbrains.com

業務が IntelliJ だもので操作感が同じというのもあるんだが、 C++リファクタリングができるというさいつよツールなのでこれを使いたい。 しかしながら CLion は cmake 形式のプロジェクトしか読み込めない。

対処

 Qt は cmake のビルドにも対応している。良い。(QtCreator から使うと恐ろしく扱いづらいが)

CMake Manual | Qt 5.4

基本はこれにしたがって設定すれば良い。あとは作った cmake プロジェクトを CLion から読みこめるので Qt を利用したコードを CLion から利用できる。 SIGANAL/SLOT などの Qt の C++ 拡張部分も問題なく使えた。

システム変数の追加

 CMAKE_PREFIX_PATH に Qt のディレクトリを追加する。僕の環境だと C:\Qt\5.3\mingw482_32 だった。 これで cmake が Qt の位置を知ることができる。

cmake の記述

# Created by Hal@shurabaP
project(sample)

# configuration for Qt
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)

# cmake options
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")

# dependency
find_package(Qt5Core)
get_target_property(QtCore_location Qt5::Core LOCATION)
find_package(Qt5Gui)
get_target_property(QtCore_location Qt5::Gui LOCATION)
find_package(Qt5Multimedia)
get_target_property(QtCore_location Qt5::Multimedia LOCATION)
find_package(Qt5Widgets)
get_target_property(QtCore_location Qt5::Widgets LOCATION)

# sources
add_executable(sample main.cpp)

target_link_libraries(sample LINK_PUBLIC Qt5::Core Qt5::Gui Qt5::Multimedia Qt5::Widgets)

cmake よく知らないから間違ってるかも。とりあえずビルドして実行できたので僕はこの設定を使っている。

C++ でエラー処理書いてたら死にそうになったので Scala の Try パクってみた。

ポエム

 業務で Scala を書いてるせいか、趣味で C++ 書いていると C++ のエラー処理のヤバさにつらみが溜まるし発狂したい。こういうのほんとうに辛い。

/**
 * path のファイルに書かれた文字列を返します。
 * エラーがあった場合は err に値が書き込まれます。
 */
string load(const string &path, int *err);

異常系の処理が貧弱すぎてつらい。何が嫌かって、きっとこの後ファイルの内容をパーズするわけで、 こんな感じの関数が作られるに違いない。

/**
 * str を json に変換します。
 * エラーがあった場合は err に値が書き込まれます。
 */
json parse(const string &str, int *err);

実際に使われるのはきっとこんな感じになるに違いない。

void main() {
  int err;
  string str(load("hoge.txt", &err));
  if(err != 0) {
    printf("File load error!!\n");
    exit(-1);
  }
  json j(parse(str, &err));
  switch(err) {
    case ...
  }
}

もうこんなの絶対発狂したい。でも例外使って try catch のハンドリングも面倒くさい。

Scala の Try パクった

上の例だとこんな感じになる。

Try<string> load(const string &path);
Try<json> parse(const string &str);

void main() {
  Try<json> result(load("hoge.txt").flatMap([](const string&str) -> Try<json>{
    return parse(str);
  }));
  if(result.isFailure()) {
    exit(-1);
  }
  ...
}

面倒くさいけどまあ伝統的な形式よりは…

 一応テストも書いたし動く模様だ。でもあんまり効率的じゃなくて重そうだな、とは思った。 あと、例外投げるところでメモリリーク発生してるよねこれ。まあいっか。

qHash 関数と名前空間

概要

 名前空間内で定義したクラスの qHash 関数の定義で手ひどい罠を踏んだので書いておく。

 これはダメなんだってさ。

namespace hoge {
  class Hoge {
    public:
    int foo;
  }
}

bool operator == (const hoge::Hoge &left, const hoge::Hoge &right) {
  return left.foo == right.foo;
}

unsigned int qHash(const hoge::Hoge& h) {
  return qHash(h);
}

こうすると行ける。

namespace hoge {
  class Hoge {
    public:
    int foo;
  }
  bool operator == (const Hoge &left, const Hoge &right) {
    return left.foo == right.foo;
  }

  unsigned int qHash(const Hoge& h) {
    return qHash(h);
  }
}

そっか。

参考資料

[QTBUG-34912] QHash compile error when using a key that is a class in a namespace - Qt Bug Tracker

音源のフォーマット考えている

Corpus-+--CorpusMetaInfo-+-name 音源名(言語別)
       |                 +-version バージョン名
       |                 +-iconPath アイコンファイル名
       |                 +-samplePath サンプル波形のファイル名
       |                 +-author 製作者(言語別)
       |                 +-web 公開ページ
       |                 +-license ライセンス文(言語別)
       |                 +-description 自由記述(言語別)
       +--PhonemeSet-+-phoneme[0] 音素片 -+-pronounce 発音
                     |                    +-label なんか識別子
                     |                    +-path ファイル名
                     |                    +-type 音素片種別 CVCとか
                     |                    +-offset 左ブランク
                     |                    +-length 音素長
                     |                    +-preutterance 位置補正
                     |                    +-loopBeginMs 左固定長
                     |                    +-koopEndMs 右固定長
                     |                    +-MusicalContext-+- noteNumber
                     |                                     +- brightness
                     |                                     +- velocity
                     |                                     +- tempo
                     |                                     +- duration
                     +-phoneme[1] 音素片 -+-...
                     |                     +-...
                     ...                   ...

こういう構造を考えた。

追記:@maruLoop氏に指摘されてライセンス・バージョン追加

nginx の reqtime が 5 秒のところにピークがある。

応答遅延と思ったら…

 5 秒のとこでピークあってどこかで詰まって返せてないのかなと思っていろいろ調べてたんだが、 User-Agent にもばらつきはないし、パスにもばらつきもないし原因が分からずずっと悩んでいた。 もう分からないので人に聞いたところ nginx には lingering_timeout という設定があるんだけどそれじゃね?と言われた。

 見たとこクライアントからのデータ送信が途切れてから、lingering_timeout の分だけ待ったのち、 接続を遮断するような設定に読める。これのデフォルト設定が 5 秒。 内部的な話は調べていないのでわからないのだが、 クライアントが不意に切断された、みたいなときに nginx 的に reqtime が lingering_timeout + αみたいになるのだろうか。

 とりあえず僕が悩んでいた件は指摘を受けてこれだったのでメモ書きにでも残す。

C++ の参照型で多態は効くのか。

経緯

 ブログも久々だが C++ も久々で、書いているとどうにもポインタを触りたくないために、できるだけ参照型で物事を済ませたかった。のだが、そういえば参照型って多態効くんだっけと思って調べたがググらビリティが低かったので自分で調べた。

結果

 効く。

test.cpp

#include <stdio.h>
 
class Base {
public:
  virtual ~Base() {}
  virtual void func() {
    printf("Base class function.\n");
  }
};
 
class ChildA : public Base {
public:
  ~ChildA() {}
  void func() {
    printf("ChildA class function\n");
  }
};
 
class ChildB : public Base {
public:
  ~ChildB() {}
  void func() {
    printf("ChildB class function\n");
  }
};
 
int main() {
  Base base;
  ChildA a;
  ChildB b;
  Base &baseRef(base);
  Base &aRef(a);
  Base &bRef(b);
  baseRef.func();
  aRef.func();
  bRef.func();
}

result

>g++ test.cpp
 
>a.exe
Base class function.
ChildA class function
ChildB class function

へー。まあでもそれもそうか。一安心。