여러 매개 변수를 반환하는 방법에는 여러 가지가 있습니다. 나는 광대 할 것이다.
참조 매개 변수를 사용하십시오.
void foo( int& result, int& other_result );
포인터 매개 변수를 사용하십시오.
void foo( int* result, int* other_result );
당신이해야 할 장점이 &
호출 사이트에서 호출 .
템플릿을 작성하여 사용하십시오.
template<class T>
struct out {
std::function<void(T)> target;
out(T* t):target([t](T&& in){ if (t) *t = std::move(in); }) {}
out(std::optional<T>* t):target([t](T&& in){ if (t) t->emplace(std::move(in)); }) {}
out(std::aligned_storage_t<sizeof(T), alignof(T)>* t):
target([t](T&& in){ ::new( (void*)t ) T(std::move(in)); } ) {}
template<class...Args> // TODO: SFINAE enable_if test
void emplace(Args&&...args) {
target( T(std::forward<Args>(args)...) );
}
template<class X> // TODO: SFINAE enable_if test
void operator=(X&&x){ emplace(std::forward<X>(x)); }
template<class...Args> // TODO: SFINAE enable_if test
void operator()(Args...&&args){ emplace(std::forward<Args>(args)...); }
};
우리는 할 수 있습니다 :
void foo( out<int> result, out<int> other_result )
그리고 모두 좋다. foo
더 이상 보너스로 전달 된 값을 읽을 수 없습니다.
데이터를 넣을 수있는 지점을 정의하는 다른 방법을 사용하여 구성 할 수 있습니다 out
. 예를 들어 어딘가에 물건을 배치하는 콜백.
구조체를 반환 할 수 있습니다 :
struct foo_r { int result; int other_result; };
foo_r foo();
whick은 모든 버전의 C ++에서 정상적으로 작동합니다. C ++ 17 이것은 또한 다음을 허용합니다.
auto&&[result, other_result]=foo();
제로 비용으로. 제거가 보장되어 매개 변수를 옮길 수도 없습니다.
우리는 다음을 반환 할 수 있습니다 std::tuple
:
std::tuple<int, int> foo();
매개 변수의 이름이 지정되지 않은 단점이 있습니다. 이것은C ++ 17:
auto&&[result, other_result]=foo();
게다가. 앞서서C ++ 17 우리는 대신 할 수 있습니다 :
int result, other_result;
std::tie(result, other_result) = foo();
조금 더 어색합니다. 그러나 보장 된 제거는 여기서 작동하지 않습니다.
낯선 영역으로 들어가면 (다음에 out<>
!) 연속 전달 스타일을 사용할 수 있습니다.
void foo( std::function<void(int result, int other_result)> );
이제 발신자는 다음을 수행합니다.
foo( [&](int result, int other_result) {
/* code */
} );
이 스타일의 이점은 메모리를 관리하지 않고도 임의의 수의 값 (균일 한 유형)을 반환 할 수 있다는 것입니다.
void get_all_values( std::function<void(int)> value )
value
콜백 할 때 500 번을 호출 할 수 있습니다 get_all_values( [&](int value){} )
.
순수한 광기를 위해 연속에서 연속을 사용할 수도 있습니다.
void foo( std::function<void(int, std::function<void(int)>)> result );
그 사용법은 다음과 같습니다.
foo( [&](int result, auto&& other){ other([&](int other){
/* code */
}) });
그 사이 많은 한 관계를 허용하는 것 result
등을 other
.
uniforn 값을 사용하면 다음과 같이 할 수 있습니다.
void foo( std::function< void(span<int>) > results )
여기서는 다양한 결과로 콜백을 호출합니다. 우리는 이것을 반복해서 할 수도 있습니다.
이를 사용하면 스택에서 할당하지 않고 메가 바이트의 데이터를 효율적으로 전달하는 기능을 가질 수 있습니다.
void foo( std::function< void(span<int>) > results ) {
int local_buffer[1024];
std::size_t used = 0;
auto send_data=[&]{
if (!used) return;
results({ local_buffer, used });
used = 0;
};
auto add_datum=[&](int x){
local_buffer[used] = x;
++used;
if (used == 1024) send_data();
};
auto add_data=[&](gsl::span<int const> xs) {
for (auto x:xs) add_datum(x);
};
for (int i = 0; i < 7+(1<<20); ++i) {
add_datum(i);
}
send_data(); // any leftover
}
이제, std::function
우리는 제로 오버 헤드없이 할당 환경에서이 일을하는 것처럼, 이것에 대한 비트 무겁습니다. 그래서 우리 function_view
는 결코 할당하지 않는 것을 원합니다 .
또 다른 해결책은 다음과 같습니다.
std::function<void(std::function<void(int result, int other_result)>)> foo(int input);
콜백 foo
을 가져와 호출하는 대신 콜백을 수행하는 함수를 반환합니다.
foo (7) ([&] (int result, int other_result) {/ * code * /}); 별도의 대괄호를 사용하여 입력 매개 변수에서 출력 매개 변수를 분리합니다.
로 variant
와c ++ 20코 루틴 foo
을 사용하면 반환 유형의 변형 (또는 반환 유형)을 생성 할 수 있습니다. 구문은 아직 수정되지 않았으므로 예제를 제공하지 않습니다.
신호 및 슬롯 세계에서 신호 세트를 노출하는 기능 :
template<class...Args>
struct broadcaster;
broadcaster<int, int> foo();
foo
비동기식으로 작동하고 완료되면 결과를 브로드 캐스트하는 을 만들 수 있습니다 .
이 줄 아래에는 다양한 파이프 라인 기술이 있는데, 여기서 함수는 어떤 기능을 수행하지 않고 데이터를 어떤 방식 으로든 연결하도록하고, 작업은 상대적으로 독립적입니다.
foo( int_source )( int_dest1, int_dest2 );
다음이 코드는하지 않습니다 할 때까지 아무것도 int_source
를 제공하기 위해 정수가 있습니다. 이 수행 할 때, int_dest1
그리고 int_dest2
그 결과를 잡 시작합니다.