ラムダ内から呼び出された場合、Decltypeを使用してリターンタイプを推定する機能テンプレートをインスタンス化することができませんか?
-
22-09-2019 - |
質問
MSVC10 RCコンパイラを使用して、C ++ 0x、特にLambda式とDecltypeを使用してコードの一部を簡素化しようとしています。
私は次の非常に奇妙な問題に遭遇します:
template <typename F>
auto foo(F f) -> decltype(f()){
return f();
}
template <typename F>
void bar(F f){
f();
}
int main() {
bar([](){
foo([]() { }); // error C2893: Failed to specialize function template ''unknown-type' foo(F)'
});
}
コメントに示されているように、コンパイラは行にエラーを生成します foo([]() { })
.
「コンパイラバグ」と叫ぶのは嫌いですが、このエラーの良い説明は本当にわかりません。どうやら、外側のラムダの表現の中で、コンパイラは専門化することはできません foo
内側のラムダの関数テンプレート。
ただし、の定義の場合 foo
このようなリターンタイプのハードコードに変更されます。
template <typename F>
void foo(F f){
return f();
}
その後、すべてが正常にコンパイルされます。
私が知らない別のラムダの範囲内に、ラムダ発現パラメーターのリターンタイプを推定するために使用される場合、dedtypeのあいまいな癖がありますか?
解決
これらは、人々が観察するためのいくつかのテストケースです。
作品
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
void dummy() {}
int main()
{
auto x = []()
{ // non-lambda parameter
foo(dummy);
};
}
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto f = [](){};
auto x = [&]()
{ // pre-defined lambda
foo(f);
};
}
失敗します
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto x = []()
{ // in-argument lambda
foo([]{});
};
}
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto x = []()
{ // in-scope lambda
auto f = []{};
foo(f);
};
}
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto x = []()
{ // in-scope lambda, explicit return
// (explicit return type fails too, `-> void`)
auto f = [](){ return; };
foo(f);
};
}
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto x = []()
{ // in-argument lambda, explicit return non-void
// (explicit return type fails too, `-> int`)
foo([]{ return 5; });
};
}
だからそれは範囲に関係しているようです そしてその (?)void
明示的にされたとしても、内部ラムダのタイプ。
他のヒント
「自動」の性質は、コンパイラがタイプを計算できるようにすることです。ただし、最初の例には互いに再帰的な参照が含まれているため、fooの自動を計算するには、バーが必要であり、fooが必要なバーのインスタンスを作成するには、fooが必要です。
一方、2番目の例では、コンパイラに「機能へのポインターである必要があるため、しばらく落ち着かせる必要がある」と明示的に伝えています。 Pointer to Functionは十分に計算されるため、タイプコンパイラは正確に予約されるものを知っています。アナログのためだけに:メンバーのフォワード宣言を比較します
struct A; //forward
...
A a1; //this is an error
A *a2; //this is correct since pointer calculated in bytes