[lv5] ft_containers(0/6) はじめに
[(1/6)vectorにすすむ] https://note.com/syamashi/n/n55ee0dad207d
Q. 何をすればゴール?
A. c++98バージョンの、便利な3つのClass、 vector/stack/map を再実装します。dockerのコンテナとは関係ありません。
setはbonusですが、mapと同じ機構です。mapを赤黒木で実装しさえすれば、setへの拡張コストはとても低いです。
#include <vector> // <= この中身を自作します
#include <stack> // <= この中身を自作します
#include <map> // <= この中身を自作します
#include <set> // <= この中身を自作します
ft::vector<int> V;
ft::stack<int> S;
ft::map<int, int> M;
ft::set<int> SE;
Q. ft::?
A. 名前空間です。
using namespace std という呪文を見たことがあれば。これは「stdという名前空間にある関数を使います」という宣言です。宣言したら、以降std::を省略して記述できる呪文です。
std::vector<int> と書けば、
namespace std{
class vector;
}
std空間のclassが呼ばれるし、
ft::vector<int> と書けば、
namespace ft{
class vector;
}
ft空間のvectorが呼ばれます。
0. テストツールを作成します。
std::の正解出力と比較できる課題なので、diffの有無で判定できる仕組みを作ります。ft::出力の目視確認はしません。
必要になるすべてのファイルを先取りします。
/testfiles/tester.hpp
#ifndef TESTER_HPP
#define TESTER_HPP
#if TEST // CREATE A REAL STL EXAMPLE
#include <iterator>
#include <map>
#include <set>
#include <stack>
#include <vector>
namespace ft = std;
#else
#include "../containers/map.hpp"
#include "../containers/set.hpp"
#include "../containers/stack.hpp"
#include "../containers/vector.hpp"
#include "../utils/algorithm.hpp"
#include "../utils/iterator.hpp"
#include "../utils/pair.hpp"
#include "../utils/util.hpp"
#endif
#include <stdlib.h>
#include <time.h> // clock()
#include <algorithm> // std::copy
#include <cmath> // hypot set
#include <cstddef> // size_t
#include <ctime>
#include <deque>
#include <iomanip>
#include <iostream> // cout
#include <list> // std::list
#include <numeric>
#include <string>
#include <typeinfo> // typeid
#define cout std::cout
#define endl std::endl
#define cerr std::cerr
#define rep(i, n) for (int i = 0; i < n; ++i)
//// tester
//// helper
#endif
Q. #if TEST
A. 定数マクロ。コンパイル時に宣言されるもので、get_next_lineでなじみがあります。
コンパイル時に -DTEST=1 でft::をstd::に置換し、std::が呼ばれ、
コンパイル時に -DTEST=0 でft::が呼ばれます。
Q.
#define cout std::cout
#define endl std::endl
#define cerr std::cerr
A. using namespace を使ってはいけないので、頻繁に使う
cout << endl;
cerr << endl;
だけ省略表記にします。
Q. #define rep(i, n) for (int i = 0; i < n; ++i)
A. for文を省略表記にします。
/testfiles/Makefile
NAME = a.out
SRCS = $(shell find *.cpp)
OBJDIR = ./obj/
OBJS = $(SRCS:%.cpp=$(OBJDIR)%.o)
CXX = clang++ -g -O0
CFLAGS = -Wall -Werror -Wextra
all: $(OBJDIR) $(NAME)
$(OBJDIR):
mkdir -p obj
$(OBJDIR)%.o: %.cpp
$(CXX) $(CFLAGS) -c -o $@ $<
$(NAME): $(OBJS)
$(CXX) $(CFLAGS) -o $(NAME) $(OBJS)
clean:
rm -rf $(OBJDIR)
rm -f out_ft out_std err_ft err_std
fclean: clean
rm -f $(NAME)
re: fclean all
Q. CXX
A. Makefileの暗黙ルールがあって、CCは.cとして認識。CXXは.cppとして認識されます。cppなので、CXXを使うのが親切。
$(OBJDIR)%.o: %.cpp
ってルールを自分で書いているので、暗黙じゃなくなり、CCでも影響ないです。
Q. CFLAGS = -Wall -Werror -Wextra
A. チュートリアル完了後に、
CFLAGS = -Wall -Werror -Wextra -std=c++98
に変更します。
ここに、便利コマンドを追加します。
test:
$(CXX) $(CFLAGS) $(SRCS) -DTEST=0 -o $(NAME)
@./$(NAME) > out_ft 2>err_ft
$(CXX) $(CFLAGS) $(SRCS) -DTEST=1 -o $(NAME)
@./$(NAME) > out_std 2>err_std
# ret(1) cause make error. ||: force ret(0)
diff out_ft out_std ||:
@echo "---ft_err---"
@cat err_ft
@echo "---std_err---"
@cat err_std
test0:
$(CXX) $(CFLAGS) $(SRCS) -DTEST=0 -o $(NAME)
@./$(NAME) > out_ft 2>err_ft
@cat out_ft
@cat err_ft
test1:
$(CXX) $(CFLAGS) $(SRCS) -DTEST=1 -o $(NAME)
@./$(NAME) > out_std 2>err_std
@cat out_std
@cat err_std
Q make test
A.
1) ft:: の標準出力をout_ftに。エラー出力をerr_ftに出力。
2) std:: の標準出力をout_stdに。エラー出力をerr_stdに出力。
3) 標準出力のdiffをとります。もしdiffがあると、エラーでMakefileが止まってしまうので、||: コマンドで強制return(0) させ、続行させます。
4) エラー出力を吐き出します。@ はターミナルに実行コマンドを表示しないオプション。
Q. tree
A.
.
├── containers
│ ├── map.hpp
│ ├── set.hpp
│ ├── stack.hpp
│ └── vector.hpp
├── testfiles
│ ├── Makefile
│ ├── main.cpp
│ ├── test_map.cpp
│ ├── test_review.cpp
│ ├── test_set.cpp
│ ├── test_stack.cpp
│ ├── test_util.cpp
│ ├── test_vector.cpp
│ └── tester.hpp
└── utils
├── algorithm.hpp
├── iterator.hpp
├── pair.hpp
├── random_access_iterator.hpp
├── rb_tree.hpp
└── util.hpp
アウトラインが出そろったので、実装していきます。
[vectorチュートリアルへ] https://note.com/syamashi/n/n55ee0dad207d
この記事が気に入ったらサポートをしてみませんか?