namespace std {
template<class InputIt, class UnaryFunction>
UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f);
}
복잡한 거 빼고,
위에 적혀있는 Unary Function 에, 한개의 인자를 가진 함수를 변수로 가진다 할 수 있겠다.
아래는 예제이다.
♣ for_each() + 함수포인터
#include <cstdio>
#include <algorithm>
using namespace std ;
int printList(int a)
{
printf("a : %d\n", a) ;
return 1 ;
}
int main()
{
int data[5] = {3, 5, 1, 13, 7} ;
// Unary Function - printList
// by 함수포인터를 사용한 방법
for_each(&data[0], &data[4], &printList) ;
return 1 ;
}
printList 함수는 한개의 인자를 가진 함수이므로 Unary Function 이다.
이 함수를 for_each() 함수의 세번째에 함수포인터로 전달하고 있다.
그러면 for_each() 함수는 data 배열의 값을 하나씩 printList 함수의 인자로 전달하고,
그 값이 전달될 때마다 printList() 함수는 호출된다.
♣ for_each() + 함수객체 (Functor)
함수객체는 굵고 짧게 얘기하면, 클래스 객체를 함수처럼 사용하겠다는 말이다.
예를 들어 아래처럼 test 란 클래스 객체를 생성했다 치자.
MyTest test = MyTest() ;
이 때, test 객체는 보통 아래처럼 쓰인다.
test.init() ;
test.destroy() ;
그런데 함수 객체(Functor) 처럼 구현되면 아래처럼 호출할 수 있다.
test(5) ;
test 는 분명 MyTest 클래스의 객체인데 마치 함수처럼 사용되고 있는 것이다.
대단하게 썼지만 연산자 오버로딩으로 구현했을 뿐이다.
본론으로 돌아와서,
Unary Function 에는 위 함수객체 또한 포함된다.
아래는 그 예제이다.
#include <cstdio>
#include <algorithm>
using namespace std ;
class TotalSum
{
public :
int getSum(){ return sum; } ;
// 아래 구현된 연산자 오버로딩으로 객체를 함수처럼 사용할 수 있다.
void operator() (int x)
{
sum += x ;
}
private :
int sum ;
};
int main()
{
int data[5] = {3, 5, 1, 13, 7} ;
// 함수 객체 (Functor) 를 이용한 방법
// for_each 함수의 반환값은 Unary Function 이다.
// 함수포인터의 경우, 이 반환값은 무시된다.
// 하지만 함수객체는 아래처럼 반환값을 받을 수 있다.
TotalSum temp = TotalSum() ;
TotalSum sum1 = for_each(&data[0], &data[5], temp) ;
printf("Sum1 : %d\n", sum1.getSum()) ;
// 굳이 클래스객체를 생성해서 넘기지 않아도 된다.
TotalSum sum2 = for_each(&data[0], &data[5], TotalSum()) ;
printf("Sum2 : %d\n", sum2.getSum()) ;
return 1 ;
}
♣ for_each() + 람다함수 ( Lamda Function)
함수포인터, 함수객체의 경우, main 함수 밖에서 따로 구현된 코드가 존재한다.
람다함수를 사용하면 for_each() 세번째 인자에서 바로 함수를 구현하여
코드를 직관적으로 짤 수 있고 inline 처럼 구현되어 프로그램 실행속도도 빨라진다고 함.
람다함수는 나도 아리까리해서 그냥 예제로 퉁친다.
#include <cstdio>
#include <algorithm>
using namespace std ;
int main()
{
int data[5] = {3, 5, 1, 13, 7} ;
// Lamda 함수를 이용한 방법
// Lamda 함수는 함수객체처럼 누적된 변수를 가질 수 없다.
// C++14 이상의 mutable 을 사용하거나 외부 변수를 사용한다.사용한다
// 아니면 위와 같이 합을 구하는 경우, accumulate() 함수를 사용할 수 있다.
// 아래는 Lamda 함수를 사용해 값을 출력하는 방법이다.
// 한줄 출력
for_each( &data[0], &data[5], [](int a) { printf("a1 : %d\n", a);});
printf("===================\n") ;
// 인자 분해.
for_each(
&data[0],
&data[5],
[](int a)
{
printf("a2 : %d\n", a);
}
);
return 1 ;
}
몇년 전, 당췌 봐도 뭔소리인지 모르던 개념 (Unary Function, functor, 람다함수 등) 이
Redmine 은 Docker 를 사용해 설치하고, DB 연동은 이미 설치된 MariaDB를 사용한다.
Redmine 은 docker-compose 를 사용하여 실행한다.
MariaDB 설치 및 docker 관련 세부 명령어는 이 글에서 다루지 않는다.
♣ docker 및 docker redmine 설치
docker, docker-compose 을 설치한다.
$ sudo apt install docker
$ sudo apt install docker-compose
$ sudo apt install docker-compose-v2
♣ MariaDB 에 Redmine 계정 생성
Redmine 자료가 저장될 MariaDB 에 Redmine 에서 사용할 계정을 만든다.
$ mysql -u root -p
로그인 되면,
1. 사용할 database 를 생성함. (아래 "redmine" 은 예제임. 수정 가능)
2. redmine DB 계정 및 패스워드 생성 (아래 "redmine" 계정 및 PW는 예제임. 수정가능)
3. 계정에 권한 부여
4. flush~
MariaDB> create database redmine ; MariaDB> create user redmine@'%' identified by 'qwerty123@' ; MariaDB> grant all privileges on redmine.* to 'redmine'@'%' ; MariaDB> flush privileges ;
♣ docker-compose 작성
compose 가 저장될 디렉토리를 하나 만들어준다. 아래는 예시이다.
$ mkdir docker-redmine
$ cd docker-redmine
compose 파일을 작성한다. 파일 생성 후,
$ vi compose.yaml
그리고 아래처럼 작성해 준다.
아래 version 은 Compose File 버전이다. 이 값은 설치된 docker 버전을 따른다.