std::invoke
関数がオーバーロードされている場合でも、関数タイプを推定する作業を行うためのラッパーを提供しようとしています。
(私は昨日、可変およびメソッドポインターバージョンについて関連する質問をしました)。
関数に1つの引数がある場合、このコード(C ++ 17)は通常の過負荷状態で期待どおりに機能します。
#include <functional>
template <typename ReturnType, typename ... Args>
using FunctionType = ReturnType (*)(Args...);
template <typename S, typename T>
auto Invoke (FunctionType<S, T> func, T arg)
{
return std::invoke(func, arg);
}
template <typename S, typename T>
auto Invoke (FunctionType<S, T&> func, T & arg)
{
return std::invoke(func, arg);
}
template <typename S, typename T>
auto Invoke (FunctionType<S, const T&> func, const T & arg)
{
return std::invoke(func, arg);
}
template <typename S, typename T>
auto Invoke (FunctionType<S, T&&> func, T && arg)
{
return std::invoke(func, std::move(arg));
}
入力引数を増やすには、明らかにコードの膨張を抑える必要がありますが、それは別の問題です。
ユーザーにconst / referencesだけが異なるオーバーロードがある場合、次のようになります。
#include <iostream>
void Foo (int &)
{
std::cout << "(int &)" << std::endl;
}
void Foo (const int &)
{
std::cout << "(const int &)" << std::endl;
}
void Foo (int &&)
{
std::cout << "(int &&)" << std::endl;
}
int main()
{
int num;
Foo(num);
Invoke(&Foo, num);
std::cout << std::endl;
Foo(0);
Invoke(&Foo, 0);
}
次にInvoke
、g ++出力を使用して、関数を誤って推定します。
(int&)
(const int&)(int &&)
(const int&)
そしてclang ++:
(int&)
(const int&)(int &&)
(int &&)
(clangの出力が異なることを指摘してくれたgezaに感謝します)。
したがってInvoke
、未定義の動作があります。
メタプログラミングがこの問題に取り組む方法だと私は思います。とにかく、Invoke
サイトで型の推論を正しく処理することは可能ですか?
(int &&)
ます。2番目のケースでは2回出力されます。
S
議論の控除と関係があるに違いない。のconst T &
バージョンをコメントアウトしてInvoke
、エラーに注意してください。また、引数が明示的に指定されている場合(Invoke<void>(&Foo, num)
)、正しいバージョンが呼び出されます。
Invoke
と、constとnon-constの両方でインスタンス化できますFoo
。また、戻り値の型(S
)が両方とも同じであるかどうかはチェックされないため、推定できませんS
。そのため、このテンプレートは無視されます。constのインスタンス化はconstでInvoke
のみ実行Foo
できるためS
、この場合は推論できます。したがって、コンパイラはこのテンプレートを使用します。