Я пытаюсь использовать C++ 0x, и в особенности лямбда-выражение и decltype для упрощения части моего кода, с помощью компилятора MSVC10 RC.
Я столкнулся со следующей очень нечетной проблемой:
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
изменяется на hardcode тип возврата, как это:
template <typename F>
void foo(F f){
return f();
}
затем все компилирует очень хорошо.
Есть ли некоторая неясная причуда decltype при использовании для выведения типа возврата параметров лямбда-выражения в объеме другой лямбды, о которой я не знаю?
Это всего лишь несколько тестовых примеров, которые люди должны наблюдать.
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
внутренней лямбды, даже если он указан явно.
Природа 'auto' в том, чтобы позволить компилятору вычислить тип. Но ваш первый пример содержит рекурсивные ссылки друг на друга, поэтому для вычисления auto's для foo вам нужен bar, а для создания экземпляра bar вам нужен foo.
С другой стороны, второй пример явно говорит компилятору: "Это должен быть указатель на функцию, так что успокойся на время". Поскольку указатель на функцию является хорошо вычисляемым типом, компилятор знает, что именно будет зарезервировано. Для аналогии: сравните прямое объявление члена
struct A; //forward
...
A a1; //this is an error
A *a2; //this is correct since pointer calculated in bytes