0

CMakeLists.txt for GraphM library

Here’s a CMakeLists.txt for GraphM library.


cmake_minimum_required(VERSION 2.8)
set(PROJ_NAME graphm)
project(${PROJ_NAME})

# set C++ flags
set(CMAKE_WARN_DEPRECATED ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -fPIC")

# for external libraries
find_package(GSL REQUIRED)
include_directories(${GSL_INCLUDE_DIRS})

## interface classes
set(modules_interface
"experiment"
"hungarian"
"rpc"
"graph"
"algorithm"
)
foreach(m ${modules_interface})
message(${m})
add_library(${m}
${m}.cpp
${m}.h
)
target_link_libraries(${m}
${GSL_LIBRARIES}
)
endforeach(m)

## graph matching algorithms
set(modules_algorithm
"algorithm_ca"
"algorithm_path"
"algorithm_ext"
"algorithm_fsol"
"algorithm_iden"
"algorithm_lp"
"algorithm_qcv"
"algorithm_rand"
"algorithm_rank"
"algorithm_umeyama"
"algorithm_unif"
)
foreach(m ${modules_algorithm})
message(${m})
add_library(${m}
${m}.cpp
${m}.h
)
target_link_libraries(${m}
${GSL_LIBRARIES}
"hungarian"
)
endforeach(m)

## main binary
add_executable(${PROJ_NAME}
main.cpp
)
target_link_libraries(${PROJ_NAME}
${GSL_LIBRARIES}
${modules_interface}
${modules_algorithm}
)
0

ノンタイプテンプレートパラメータ

関数・クラステンプレートのテンプレートパラメータに型以外を使う時,そのパラメータはノンタイプテンプレートパラメータと呼ばれる.

一般的に定数の整数値(enumeratorを含む)や外部リンケージのオブジェクトへのポインタを使う.
浮動小数点数やクラス型のオブジェクトは使えない.

以下のように,整数値をテンプレートパラメータとして使いたい場合は,const int で定義した整数値か整数値を直打ちする.

/// myTemplate.hpp
#ifndef __MYTEMPLATE_HPP__
#define __MYTEMPLATE_HPP__

// 関数テンプレートのノンタイプパラメータ
template <int SIZE>
int addSpecial(int x)
{
    return x + SIZE;
}

// クラステンプレートのノンタイプパラメータ
template <int SIZE>
class myArray
{
public:
    myArray();
public:
    float elements[SIZE];
};

template <int SIZE>
myArray<SIZE>::myArray()
{
    for(int n = 0; n < SIZE; ++n)
    {
        elements[n] = static_cast<float>(n);
    }
}

#endif // end of __MYTEMPLATE_HPP__

/// main.cpp
#include <iostream>
#include "myTemplate.hpp"

int main()
{
    std::cout << addSpecial<1>(3) << std::endl;
    std::cout << addSpecial<2>(3) << std::endl;
    std::cout << addSpecial<3>(3) << std::endl;

    const int size_5 = 5;
    myArray<size_5> v_5;

    for(int n = 0; n < size_5; ++n)
    {
        std::cout << v_5.elements[n] << std::endl;
    }

    myArray<3> v_3;

    for(int n = 0; n < 3; ++n)
    {
        std::cout << v_3.elements[n] << std::endl;
    }

	return 0;
}
0

templateの明示的インスタンス化 (explicit instantiation)

templateの明示的インスタンス化とは,宣言と定義が別ファイルに記述してある関数テンプレート・クラステンプレートを呼ぶ時に必要.
コンパイラが関数テンプレートやクラステンプレートをインスタンス化する時,どのようなテンプレート引数でインスタンス化されるのかコンパイラが知っておく必要がある.関数・クラステンプレートの宣言・定義を別ファイルに分けた場合,関数・クラスの定義とその関数・クラスを使用する,すなわち使用されるテンプレート引数を知っているファイルが別々に別れていることになる.そのため,リンカエラーが起きる.

例として,入力引数の二乗を計算するsquare関数を関数テンプレートとして,以下のように別のファイルに宣言・定義してみる.このコードをコンパイルすると,main.cppの関数テンプレートを呼ぶ行でリンカエラー「LNK2019: unresolved external symbol」が発生する.

/// myTemplate.hpp
#ifndef __MYTEMPLATE_HPP__
#define __MYTEMPLATE_HPP__

template <typename T>
T square(const T x);

#endif // end of __MYTEMPLATE_HPP__
/// myTemplate.cpp
#include "myTemplate.hpp"

template <typename T>
T square(const T x)
{
return x * x;
}
/// main.cpp
#include <iostream>
#include "myTemplate.hpp"

int main()
{
int x_i = 3;
float x_f = 3.5;
double x_d = 4.1;

std::cout << x_i << "^2 = " << square(x_i) << std::endl;
std::cout << x_f << "^2 = " << square(x_f) << std::endl;
std::cout << x_d << "^2 = " << square(x_d) << std::endl;

return 0;
}

解決策は幾つかあるが,どれも一長一短.

1. 包含モデル (inclusion model)
テンプレートを宣言するヘッダ内に定義を記述することで,テンプレートが全てインスタンス化されることを保証する.非常に単純な解決策.
問題点はヘッダファイルをインクルードするコストが増える,つまりコンパイルにかかる時間が長くなる点.

/// myTemplate.hpp
#ifndef __MYTEMPLATE_HPP__
#define __MYTEMPLATE_HPP__

template <typename T>
T square(const T x)
{
return x * x;
}

#endif // end of __MYTEMPLATE_HPP__

2. 明示的インスタンス化 (explicit instantiation)
手動でテンプレートをインスタンス化する.明示的なインスタンス化を行うには,templateキーワードの後にインスタンス化したいテンプレート引数を全て記述する宣言をする.(1)関数テンプレートの宣言後に明示的インスタンス化を行うか,(2)別のファイルで明示的インスタンス化を行うか,どちらでも良い.
欠点は,関数・クラステンプレートがどの型でインスタンス化されたか常に意識しなければいけない点,テンプレート化したのに明示的にインスタンス化しなければいけない,つまり型を意識しなければいけないのは矛盾しているように思える点.

// 関数テンプレートの宣言後に明示的インスタンス化
/// myTemplate.cpp
#include "myTemplate.hpp"

template <typename T>
T square(const T x)
{
return x * x;
}

template int square(const int x);
template float square(const float x);
template double square(const double x);
// 別のファイルで明示的インスタンス化
/// main.cpp
#include "myTemplate.cpp"

template int square(const int x);
template float square(const float x);
template double square(const double x);

関数テンプレートに限らず,クラステンプレートも明示的インスタンス化ができる.
クラステンプレートをインスタンス化すると,自動的に全てのメンバ関数がインスタンス化される.
クラステンプレートの一部のメンバ関数のみをインスタンス化することも可能.

0

C++のためのAPIデザイン

C++のためのAPIデザイン
Martin Reddy (著),ホジソン ますみ (翻訳),三宅 陽一郎 (監修)
ソフトバンククリエイティブ

タイトルとは異なり,C++に限らないAPIの設計に関する話も含まれている.必読の一冊と言える.と固く書いてみたけど,卒論レベルのプログラムでも,この本を読んでから書いた方が良いと思う.

内容: 自由度の高い言語C++の可能性を引き出す、珠玉の12章。長期の運用に堪える安全なソフトウェア設計のために。(「BOOK」データベースより)

0

Effective Modern C++ C++11/14プログラムを進化させる42項目

Effective Modern C++ C++11/14プログラムを進化させる42項目
Scott Meyers (著),千住 治郎 (訳)
O’REILLY

C++11/14について色々と勉強.と言っても,現時点でC++11までしか使っていない.自分のコードに今すぐ反映させている内容は

  • auto
  • オブジェクト作成時の()と{}
  • using (エイリアス)
  • scoped enum
  • const_iteratorの優先
  • スマートポインタ (今のところメンバ変数の前方宣言でのみ使用)

内容: C++11/C++14対応!C++界のカリスマが贈る「Effective C++」シリーズ最新刊! (「BOOK」データベースより)