C++에서는 객체를 마치 함수처럼 사용 가능한 펑터가 존재한다.
펑터는 다른 말로 함수객체, 함수자, 펑션옵젝트등 많은 이름이 존재한다.(하지만 결국 다 같은말)
쉽게 생각해서 C의 함수포인터를 class의 형태로 써먹는다고 생각하면 될것 같다.
이전 스마트포인터 처럼 함수를 객체로 랩퍼 했다고 생각하면 편할것 같다.
일단 소스를 보자
#include <iostream>
#define MAX 10
struct Rule
{
// Fucntor
bool operator()(int x, int y) const
{
return (x > y) ? true : false
}
};
객체를 가지고 함수처럼 작동 시킨다고 했는데 웬 구조체가 등장했다.
한가지 짚고 넘어가야 할 것은 C++에서는 class나 struct 나 100프로 동일하다.
차이점이라면 단지 struct 는 모든 맴버를 public으로 자동 지정하는 것이고, class 는 private로 지정하는 것이 차이이다.
위에서 struct를 사용한 이유도 굳이 public: 키워드를 사용할 필요가 없기때문이다.
연산자 오버로딩을 통해 () 연산자를 오버로딩 했다. 두개의 정수를 받아 앞의 정수가 크다면 true , 뒤에 정수가 크다면 false 를 리턴하는
간단한 연산자 오버로딩 함수이다.
void PrintArray(int* arry);
void Sort(int* arry, const Rule& functor);
int main()
{
int arry[MAX] = {2, 5, 1, 7, 9, 3, 4, 6, 8, 0};
// 정렬전출력
PrintArray(arry);
// 펑터(룰)을가지고정렬(임시객체이용)
Sort(arry, Rule());
// 펑터(룰)을가지고정렬(객체생성후)
//Rule r;
//Sort(arry, r);
// 정렬후출력
PrintArray(arry);
return 0;
}
main 함수 부분이다. Sort 함수에 Rule() 형태로 객체를 전달하는데 이는 Rule (디폴트 생성자) 를 호출한 임시 객체이다.
아래줄에서는 혼동을 없애기 위해 애초에 객체를 생성하고 객체를 넘기고 있다.
저게 함수같다고 생각하면 안되니 주의하자.
void PrintArray(int* arry)
{
for (int i = 0; i < MAX i++)
{
std::cout << arry[i] << " "
}
std::cout << std::endl
}
void Sort(int* arry, const Rule& functor)
{
int temp
for (int i = 0; i < MAX - 1; i++)
{
for (int j = i + 1; j < MAX j++)
{
// 펑터를가지고값비교
if (functor(arry[i], arry[j]))
{
temp = arry[i];
arry[i] = arry[j];
arry[j] = temp
}
}
}
}
다른 부분은 볼필요 없고 값 비교 부분에서
넘어온 객체를 가지고 함수처럼 사용하고 있다.
이는 위에서 정의한 operator() 연산자를 사용한 것이다.
펑터는 STL에서 많이 사용되므로 꼭 알아두어야 겠다.
Haskell 입문서 등을 보면 대개 꼭 다루는 게 Eq, Show, Read, Ord, Num 등등과 같은 type class들을 다루고,
중반이나 후반부에 Functor, Applicative Functor, Monad, Monoid 등이 등장한다. 그 때부터는 슬슬 헷갈리기 시작한다...
"아하~~~" 하고 이해했나 싶은데 다음 날 보면 또 모르겠고.
"아 그래서 도대체 이걸 언제 어느 때 어느 곳에 쓰라는겨" 같은 생각이 스멀스멀 기어오른다.
맨 처음에 type class라는 개념을 접했을 때 혼란의 극치였다.
다른 OOP 언어들에서 말하는 class 라던가 polymorphism 등이 하스켈에서는 너무 개념이 달랐기 때문에.
그나마 이전에 LISP을 접해놔서 '함수도 데이터처럼 취급하는' 특성에는 나름 쉽게 적응했지만...
암튼 이런 특징들은 ALGOL 언어의 후손격 언어들(C, Pascal 같은 Imperative언어들, 또 그 영향을 많이 받은 C++, Java 같은 OOP언어들)에 익숙했던 사람들에겐 생소한 개념이리라...
구글 검색 중에 "Typeclassopedia"라는 자료를 보게 되었는데, 다음과 같은 취지로 쓰여졌다고 한다.
"standard type classes에 대해 확고한 이해를 바라는 학생들에게 시작점으로서의 역할"
"type에 대해 잘 이해하고, 각각의 type class들과 그들 사이의 관계에 대해 깊은 통찰력을 얻는 것"
Functor, Applicative, Monad 등의 관계가 정리된 자료
실제로 Haskell을 공부하다 보면, 다음과 같은 궁금증이 솟구칠 때가 있다.
"Functor가 뭐지?"
"Functor와 Applicative functor와 Monad? 걔네 뭐야? 그 놈이 그 놈 같고 다 비슷하게 생겼는데"
"그래서 걔네들끼리는 무슨 관계야?"
"Monoid는 또 뭐야, Monad 친척인가..."
"MonadPlus라는 것도 있네?
뭐 그런 류의 의뭉스러운 점들 등등... 꽤 많다.
하스켈은 개념이 상당히 추상적인 게 많아서 (누군가는 우아하고 고상하다고 하겠지만) 좀 난해한 면이 없잖아 있다.
표현력이 지나치게 좋다고 해야 하나...
그래서 어느 선을 넘어가버리면 오히려 코드가 암호처럼 보이기 시작한다 ㅋㅋㅋㅋ
너무 한 줄 한 줄에 많은 내용이 담길 때가 많아서 말이지.
암튼 이 자료는 그런 의문점에 어느 정도 도움을 주는 자료라고 할 수 있다.
아래 그림은 글 초반부에 나오는 건데, 여러 standard type class들간의 관계를 보여주고 있다.
글 본론은 Functor, Applicative, Monoid, Monad 등 주요하게 사용되는 type class들을 설명하고 예시를 들고... 그런 식으로 구성되어 있다.
하스켈 입문서 한 권 정도 보고, type class에 대한 이해를 어느 정도 한 뒤에 보면 좋을 듯.
펑크터 펑크터 하면 모르길레 쓰는 뻘글
펑크터(functor)-> 함수자
쉽게 풀어쓰면
함수 같은 객체(function like object)
정도로 번역되는 물건이다.
객체는 객체인데
함수랑 하는일이 같은 객체다.
(함수랑 거의 같다는것에 착안해서 함수 객체(function object)라고 부르기도
한다.)
예는 많은 곳에 널렷지만 the c++ programming language에 나온것을
조금 인용해 본다.
template<typename T> class Sum
{
T res;
public:
Sum(T i = 0) : res(i) {}
void operator()(T x) {
res += x;
}
T result() const {
return res;
}
};
위와 같은게 펑크터다.
하는것도 없는 클레스 같지만 다음과 같은 곳에 쓰인다.
(역시 같은책의 예제다)
void f(std::list<double>& ld)
{
Sum<double> s;
s = std::for_each(ld.begin(), ld.end(), s);
std::cout<< s.result();
}
for_each는 그냥 begin에서 end바로
전까지 적당한 연산을 호출해서 각 원소에 적용 하는 함수다.
여기선 그 적당한연산 대신 s라는 객체를 넘겨줫고
for_each는 s안에 있는 호출할만한 적당한 함수 하나를 호출할 뿐이다.
사실상 s는 객체의 모양을한 함수에 불과한거.
장점?
중간값을 유지할수 있다는 것(s는 객체니까) 과
종종 함수보다 객체가 더 빠르기도 하다는것.(클레스는
inline이 가능하니까)
별거 아닌게 펑크터다.
# |
|
함수처럼 행동하는 객체를 정의하여 함수-객체라 한다.
즉, 함수처럼 괄호를 사용하여 호출할수 있고, 인자도 전달할수 있는 클래스를 말한다.
만드는 방식은 적합한 Parameter 타입과 함께 ()연산자를 오버로딩 시켜서 사용한다.
class X
{
public:
리턴값 operator() (전달할 argument) const;
}
낯설기도 하고 다루기 어렵기도 하지만
함수에 비해 3가지 장점이 있다
1. 스마트 함수이다
포인터처럼 행동이 가능하기에 스마트 포인터(포인터와 동일한 인터페이스를가지면서 더 추가적인 기능을 수행하는 객체)의 일종이기도하다. Functor는 어디까지나 클래스이기에 다른 멤버 변수들이나
멤버 함수들을 가질수 있다는 것으로, 같은 functor라도 다른상태를 가질수 있다는 것을 의미한다. 또한 호출하기 전에 functor는 컴파일시가 아닌 런타임시에 초기화도 할수있다
2. 각각의 functor는 자신만의 타입을 가지고 있다.
기존의 함수들은 signature가 다를 경우에만 다른 타입을 가질수 있지만 functor는 그런거 상관없이 signature가 동일해도 다른 타입을 가질수 있다.
이는 generic한 프로그래밍이 가능하다는 것을 의미하며(기능적인 동작들을 템플릿인자로 제공가 능하므로)다른 타입의 컨테이너에 대해서 정렬기준으로 같은 종류의 functor를 사용할수 있다. 또한 계층구조를 작성하는 것 도 가능하다
3. 기존 함수보다 빠르다
template으로 정의되므로 컴파일 타임시에 더욱 자세한 정보들을 정의하고 있으며
모두 인라인화 되어있으며 알고리즘에서 인자값으로 받아 들일때 알고리즘들은
일반함수는 함수포인터로 처리하기 때문에 인라인화 시키지 않는다
때문에 더욱 좋은 최적화를 제공한다.
STL에서는 몇가지 정의된 functor를 제공하는데 이중 일부를 소개한다.
negate -> 컬렉션의 원소에 negate(부정:음수면 양수 양수면 음수)로 변환한다
multiplies -> 1,2 번 컬렉션을 4번 동작으로 결합하여 그 결과를 3번째 컬렉션에 저장한다.
less -> 컬렉션의 원소보다 낮은 값을 반환한다. less_equal
greater -> 컬렉션의 원소보다 높은 값을 반환한다 greate_equal
equal_to -> 컬렉션의 원소와 같은 값을 반환한다
.
mem_fun_ref(&class::class멤버함수) -> 원소에 대해서 명시된 클래스의 멤버변수를 호출한다.
즉 해당 컬렉션에 모든 원소에 대해서 class에 class멤버함수를 호출한다. 단. 원소가 해당 class 타입이거나 class에서 파생된 타입을 가질경우에만 유효하다
C++
펑터는 다른 말로 함수객체, 함수자, 펑션옵젝트등 많은 이름이 존재한다.(하지만 결국 다 같은말)
쉽게 생각해서 C의 함수포인터를 class의 형태로 써먹는다고 생각하면 될것 같다.
이전 스마트포인터 처럼 함수를 객체로 랩퍼 했다고 생각하면 편할것 같다.
일단 소스를 보자
<iostream>
MAX 10
Rule
객체를 가지고 함수처럼 작동 시킨다고 했는데 웬 구조체가 등장했다.
한가지 짚고 넘어가야 할 것은 C++에서는 class나 struct 나 100프로 동일하다.
차이점이라면 단지 struct 는 모든 맴버를 public으로 자동 지정하는 것이고, class 는 private로 지정하는 것이 차이이다.
위에서 struct를 사용한 이유도 굳이 public: 키워드를 사용할 필요가 없기때문이다.
연산자 오버로딩을 통해 () 연산자를 오버로딩 했다. 두개의 정수를 받아 앞의 정수가 크다면 true , 뒤에 정수가 크다면 false 를 리턴하는
간단한 연산자 오버로딩 함수이다.
PrintArray(int* arry);
Sort(int* arry, const Rule& functor);
main()
main
아래줄에서는 혼동을 없애기 위해 애초에 객체를 생성하고 객체를 넘기고 있다.
저게 함수같다고 생각하면 안되니 주의하자.
PrintArray(int* arry)
Sort(int* arry, const Rule& functor)
다른 부분은 볼필요 없고 값 비교 부분에서
넘어온 객체를 가지고 함수처럼 사용하고 있다.
이는 위에서 정의한 operator() 연산자를 사용한 것이다.
펑터는 STL에서 많이 사용되므로 꼭 알아두어야 겠다.
C++
펑터는 다른 말로 함수객체, 함수자, 펑션옵젝트등 많은 이름이 존재한다.(하지만 결국 다 같은말)
쉽게 생각해서 C의 함수포인터를 class의 형태로 써먹는다고 생각하면 될것 같다.
이전 스마트포인터 처럼 함수를 객체로 랩퍼 했다고 생각하면 편할것 같다.
일단 소스를 보자
<iostream>
MAX 10
Rule
객체를 가지고 함수처럼 작동 시킨다고 했는데 웬 구조체가 등장했다.
한가지 짚고 넘어가야 할 것은 C++에서는 class나 struct 나 100프로 동일하다.
차이점이라면 단지 struct 는 모든 맴버를 public으로 자동 지정하는 것이고, class 는 private로 지정하는 것이 차이이다.
위에서 struct를 사용한 이유도 굳이 public: 키워드를 사용할 필요가 없기때문이다.
연산자 오버로딩을 통해 () 연산자를 오버로딩 했다. 두개의 정수를 받아 앞의 정수가 크다면 true , 뒤에 정수가 크다면 false 를 리턴하는
간단한 연산자 오버로딩 함수이다.
PrintArray(int* arry);
Sort(int* arry, const Rule& functor);
main()
main
아래줄에서는 혼동을 없애기 위해 애초에 객체를 생성하고 객체를 넘기고 있다.
저게 함수같다고 생각하면 안되니 주의하자.
PrintArray(int* arry)
Sort(int* arry, const Rule& functor)
다른 부분은 볼필요 없고 값 비교 부분에서
넘어온 객체를 가지고 함수처럼 사용하고 있다.
이는 위에서 정의한 operator() 연산자를 사용한 것이다.
펑터는 STL에서 많이 사용되므로 꼭 알아두어야 겠다.
C++
펑터는 다른 말로 함수객체, 함수자, 펑션옵젝트등 많은 이름이 존재한다.(하지만 결국 다 같은말)
쉽게 생각해서 C의 함수포인터를 class의 형태로 써먹는다고 생각하면 될것 같다.
이전 스마트포인터 처럼 함수를 객체로 랩퍼 했다고 생각하면 편할것 같다.
일단 소스를 보자
<iostream>
MAX 10
Rule
객체를 가지고 함수처럼 작동 시킨다고 했는데 웬 구조체가 등장했다.
한가지 짚고 넘어가야 할 것은 C++에서는 class나 struct 나 100프로 동일하다.
차이점이라면 단지 struct 는 모든 맴버를 public으로 자동 지정하는 것이고, class 는 private로 지정하는 것이 차이이다.
위에서 struct를 사용한 이유도 굳이 public: 키워드를 사용할 필요가 없기때문이다.
연산자 오버로딩을 통해 () 연산자를 오버로딩 했다. 두개의 정수를 받아 앞의 정수가 크다면 true , 뒤에 정수가 크다면 false 를 리턴하는
간단한 연산자 오버로딩 함수이다.
PrintArray(int* arry);
Sort(int* arry, const Rule& functor);
main()
main
아래줄에서는 혼동을 없애기 위해 애초에 객체를 생성하고 객체를 넘기고 있다.
저게 함수같다고 생각하면 안되니 주의하자.
PrintArray(int* arry)
Sort(int* arry, const Rule& functor)
다른 부분은 볼필요 없고 값 비교 부분에서
넘어온 객체를 가지고 함수처럼 사용하고 있다.
이는 위에서 정의한 operator() 연산자를 사용한 것이다.
펑터는 STL에서 많이 사용되므로 꼭 알아두어야 겠다.
C++
펑터는 다른 말로 함수객체, 함수자, 펑션옵젝트등 많은 이름이 존재한다.(하지만 결국 다 같은말)
쉽게 생각해서 C의 함수포인터를 class의 형태로 써먹는다고 생각하면 될것 같다.
이전 스마트포인터 처럼 함수를 객체로 랩퍼 했다고 생각하면 편할것 같다.
일단 소스를 보자
<iostream>
MAX 10
Rule
객체를 가지고 함수처럼 작동 시킨다고 했는데 웬 구조체가 등장했다.
한가지 짚고 넘어가야 할 것은 C++에서는 class나 struct 나 100프로 동일하다.
차이점이라면 단지 struct 는 모든 맴버를 public으로 자동 지정하는 것이고, class 는 private로 지정하는 것이 차이이다.
위에서 struct를 사용한 이유도 굳이 public: 키워드를 사용할 필요가 없기때문이다.
연산자 오버로딩을 통해 () 연산자를 오버로딩 했다. 두개의 정수를 받아 앞의 정수가 크다면 true , 뒤에 정수가 크다면 false 를 리턴하는
간단한 연산자 오버로딩 함수이다.
PrintArray(int* arry);
Sort(int* arry, const Rule& functor);
main()
main
아래줄에서는 혼동을 없애기 위해 애초에 객체를 생성하고 객체를 넘기고 있다.
저게 함수같다고 생각하면 안되니 주의하자.
PrintArray(int* arry)
Sort(int* arry, const Rule& functor)
다른 부분은 볼필요 없고 값 비교 부분에서
넘어온 객체를 가지고 함수처럼 사용하고 있다.
이는 위에서 정의한 operator() 연산자를 사용한 것이다.
펑터는 STL에서 많이 사용되므로 꼭 알아두어야 겠다
C++
펑터는 다른 말로 함수객체, 함수자, 펑션옵젝트등 많은 이름이 존재한다.(하지만 결국 다 같은말)
쉽게 생각해서 C의 함수포인터를 class의 형태로 써먹는다고 생각하면 될것 같다.
이전 스마트포인터 처럼 함수를 객체로 랩퍼 했다고 생각하면 편할것 같다.
일단 소스를 보자
<iostream>
MAX 10
Rule
객체를 가지고 함수처럼 작동 시킨다고 했는데 웬 구조체가 등장했다.
한가지 짚고 넘어가야 할 것은 C++에서는 class나 struct 나 100프로 동일하다.
차이점이라면 단지 struct 는 모든 맴버를 public으로 자동 지정하는 것이고, class 는 private로 지정하는 것이 차이이다.
위에서 struct를 사용한 이유도 굳이 public: 키워드를 사용할 필요가 없기때문이다.
연산자 오버로딩을 통해 () 연산자를 오버로딩 했다. 두개의 정수를 받아 앞의 정수가 크다면 true , 뒤에 정수가 크다면 false 를 리턴하는
간단한 연산자 오버로딩 함수이다.
PrintArray(int* arry);
Sort(int* arry, const Rule& functor);
main()
main
아래줄에서는 혼동을 없애기 위해 애초에 객체를 생성하고 객체를 넘기고 있다.
저게 함수같다고 생각하면 안되니 주의하자.
PrintArray(int* arry)
Sort(int* arry, const Rule& functor)
다른 부분은 볼필요 없고 값 비교 부분에서
넘어온 객체를 가지고 함수처럼 사용하고 있다.
이는 위에서 정의한 operator() 연산자를 사용한 것이다.
펑터는 STL에서 많이 사용되므로 꼭 알아두어야 겠다
C++
펑터는 다른 말로 함수객체, 함수자, 펑션옵젝트등 많은 이름이 존재한다.(하지만 결국 다 같은말)
쉽게 생각해서 C의 함수포인터를 class의 형태로 써먹는다고 생각하면 될것 같다.
이전 스마트포인터 처럼 함수를 객체로 랩퍼 했다고 생각하면 편할것 같다.
일단 소스를 보자
<iostream>
MAX 10
Rule
객체를 가지고 함수처럼 작동 시킨다고 했는데 웬 구조체가 등장했다.
한가지 짚고 넘어가야 할 것은 C++에서는 class나 struct 나 100프로 동일하다.
차이점이라면 단지 struct 는 모든 맴버를 public으로 자동 지정하는 것이고, class 는 private로 지정하는 것이 차이이다.
위에서 struct를 사용한 이유도 굳이 public: 키워드를 사용할 필요가 없기때문이다.
연산자 오버로딩을 통해 () 연산자를 오버로딩 했다. 두개의 정수를 받아 앞의 정수가 크다면 true , 뒤에 정수가 크다면 false 를 리턴하는
간단한 연산자 오버로딩 함수이다.
PrintArray(int* arry);
Sort(int* arry, const Rule& functor);
main()
main
아래줄에서는 혼동을 없애기 위해 애초에 객체를 생성하고 객체를 넘기고 있다.
저게 함수같다고 생각하면 안되니 주의하자.
PrintArray(int* arry)
Sort(int* arry, const Rule& functor)
다른 부분은 볼필요 없고 값 비교 부분에서
넘어온 객체를 가지고 함수처럼 사용하고 있다.
이는 위에서 정의한 operator() 연산자를 사용한 것이다.
펑터는 STL에서 많이 사용되므로 꼭 알아두어야 겠다