이 두 개의 고차 함수 정의 사이에 차이점이 있습니까?
4개의 주요 문구 사이에 차이점이 있습니까?저는 apply2(&func)만 말이 된다고 생각합니다.그러나 4개 모두 동일한 값을 반환합니다.
int func(void)
{
return 1;
}
int apply1( int f1(void) )
{
return f1();
}
int apply2( int (*f1) (void) )
{
return f1();
}
int main()
{
apply1(func);
apply1(&func);
apply2(func);
apply2(&func);
return 0;
}
먼저, 함수 포인터는 어렵습니다.어떤 함수를 다른 함수에 매개 변수로 전달할 수 있다고 생각하는 것은 재귀를 이해하는 것과 유사한 마음의 동요를 필요로 합니다.처음에는 이해하지 못하겠지만, 갑자기 뇌에 이해의 홍수문이 열리고 깨달음을 얻는 것과 같습니다.
그러나 C와 C++에서 매개 변수로 함수를 전달하는 규칙을 알아야 합니다.이러한 언어에서는 기능이 1등 시민이 아니기 때문에 기능으로 할 수 있는 작업에 많은 제약이 있습니다.
구문
함수 포인터 구문이 조금 못생겼습니다.기본 해부학적 구조는[return type] (*[name])([argument list])
주변 괄호*name
는 함수 포인터와 포인터를 반환하는 함수 사이를 명확하게 구분하는 데 필요합니다.
// not function pointers: * not grouped to function name
int x(); // function that returns an int
int* x(); // function that returns an int*
int *x(); // also a function that returns an int*, spaces don't matter
// function pointers: * grouped to function name
int (*x)(); // pointer to a function that returns an int
int* (*x)(); // pointer to a function that returns an int*
붕괴
매개 변수로 전달하는 측면에서 함수는 배열과 거의 동일하게 동작합니다.통과하면 포인터로 바뀝니다.비교:
void Foo(int bar[4]); // equivalent to: void Foo(int* bar)
void Bar(int baz()); // equivalent to: void Bar(int (*baz)())
이는 단순히 함수와 어레이를 할당할 수 없고 복사할 수 없기 때문입니다.
int foo[4];
int bar[4] = foo; // invalid
int foo();
int bar() = foo; // invalid
따라서 이들을 함수 매개변수로 전달하는 유일한 방법은 해당 매개변수를 복사하는 대신 주소를 전달하는 것입니다. (이것은 배열에서는 논쟁의 여지가 있지만, 그렇게 작동합니다.)이러한 "값"이 매개 변수로 전달될 때 포인터로 변환된다는 사실을 "쇠퇴"라고 합니다.
이 두 프로토타입은 호환되며(즉, 동일한 기능을 의미하며, 서로 다른 과부하가 아닙니다), 따라서 두 프로토타입 사이에는 차이가 없습니다.
int foo(void bar());
int foo(void (*bar)());
시각적인 측면은 차치하고, 그 두 선언 사이에는 전혀 차이가 없습니다.두 함수 모두 함수 포인터를 사용할 수 있습니다. 함수 포인터의 모양과 모양에 관계없이 함수 포인터는 감쇠로 인해 사용할 수 있습니다.그러나, 붕괴는 종종 불쾌하고 혼란스러운 것으로 여겨지기 때문에, 대부분의 개발자들은 함수 포인터를 명시적으로 요청하는 것을 선호할 것입니다(그리고 많은 개발자들은 함수 유형이 붕괴될 수 있다는 것조차 알지 못합니다).
암시적 변환
이제 함수를 매개 변수로 전달합니다.이것은 단순히 붕괴의 결과입니다. 함수는 암시적으로 함수 포인터 유형으로 변환되어야 합니다.이것은 함수 포인터가 필요한 곳에 함수를 전달할 수 있다는 것을 의미하며 컴파일러는 그 주소를 얻을 것입니다.이러한 목적을 위해 다시 한 번 다음과 같습니다.
int foo();
int (*bar)() = foo; // the compiler implicitly assigns the address of foo to bar
int (*baz)() = &foo; // you explicitly assign the address of foo to baz
이 두 가지 설명을 결합하면 네 가지 함수 호출이 모두 같다는 것을 알게 될 것입니다. apply1
그리고.apply2
다 변수를 합니다(" 다 동 한허모다니용합를수둘유형의일(다▁both니▁(합둘"()).int (*)(void)
)에, 에 대해서는 명확하지 않습니다.apply1
리고함 호때할출로 때.func
에 &func
컴파일러는 암시적으로 당신을 위해 주소를 가져가고 그것을 동등하게 만듭니다.&func
.
다음은 질문의 범위를 벗어난 내용이지만 앞 부분을 자세히 설명하고 있고, 좀 깔끔하다고 생각합니다.
함수 참조 [C++ 전용]
잘 알려지지 않은 사실이지만 배열 및 함수에 대한 참조를 전달할 수도 있습니다. 이 경우에는 붕괴가 발생하지 않습니다.다음과 같이:
void Foo(int (&bar)[4]); // NOT equivalent to void Foo(int* bar)
void Bar(int (&baz)()); // NOT equivalent to void Bar(int (*baz)())
이 시나리오에서는 포인터 유형과 참조 유형 간에 암묵적인 변환이 없으므로 연산자의 주소를 사용할 수 없습니다.부패를 물리치는 것은 일반적으로 좋은 것으로 여겨지는데, 부패는 종종 혼란스럽기 때문입니다.
int baz();
Bar(baz); // valid
Bar(&baz); // INVALID
함수 참조는 일반 참조와 동일한 규칙을 따릅니다. 정의 시에만 할당할 수 있으며 null일 수 없습니다.
유형ef
다음을 사용하여 함수 포인터를 덜 못생기게 만들 수 있습니다.typedef
.
typedef int (*X)();
X func; // func is a pointer to a function that returns an int
당신이 그것을 꺼내면 더 흥미로워집니다.(*)
표시된 항목:
typedef int X();
X* func; // func is a function pointer
X& func; // func is a function reference [C++ only]
X func; // func is a function declaration (!!)
의 경우에는, 의경우는에후자,는,X func;
다음과 같은 선언문에 해당합니다.int func();
모두를 혼란스럽게 하고 싶지 않다면 집에서 이런 짓을 하지 마세요.
decltype
[해당].이를 만듭니다 [C++만 해당]
함수와 함수 포인터 사이의 또 다른 흥미로운 차이는 다음의 사용과 함께 발생합니다.decltype
.decltype
익스프레스의 유형을 "수정"합니다.이 구성의 경우 다음과 같은 차이가 있습니다.function
그리고.&function
:
int bar();
decltype(bar); // type is int ()
decltype(&bar); // type is int (*)()
이 차이는 템플릿 매개 변수로 유형을 전달하려는 경우 특히 중요합니다.std::unique_ptr
.
std::unique_ptr<void, decltype(free)> foo; // INVALID
std::unique_ptr<void, decltype(&free)> foo; // valid
. 첫 는 " 번는다인스필스함드않다습니유하지첫효하"의 인스턴스 를 생성하려고 하기 입니다.unique_ptr
.
언급URL : https://stackoverflow.com/questions/18626080/are-there-any-differences-between-these-two-higher-order-function-definitions
'programing' 카테고리의 다른 글
토네이도 사용 시기, 트위스트 / 사이클론 / GEVENT / 기타 (0) | 2023.06.21 |
---|---|
Spring 5 Reactive에서의 HTTP 응답 예외 처리 (0) | 2023.06.21 |
두 절대 경로를 비교하여 상대 경로 가져오기 (0) | 2023.06.21 |
loadurl을 호출할 때 Android 웹 보기가 브라우저를 시작합니다. (0) | 2023.06.21 |
Firebase Cloud Messaging을 사용하여 장치를 장치 메시지로 보내는 방법은 무엇입니까? (0) | 2023.06.16 |