複数のパラメーターを返す方法はたくさんあります。私は疲れきっています。
参照パラメーターを使用します。
void foo( int& result, int& other_result );
ポインタパラメータを使用します。
void foo( int* result, int* other_result );
これには、&
呼び出しサイトでaを実行する必要があるという利点があります。
テンプレートを作成して使用します。
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 */
}) });
との間の多対1の関係を許可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
、結果の受信を開始します。