Не мог инстанцировать шаблонов функций, который использует decltype для выведения типа возврата, если названо из лямбды?

Я пытаюсь использовать 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 при использовании для выведения типа возврата параметров лямбда-выражения в объеме другой лямбды, о которой я не знаю?

9
задан Jon Seigel 5 March 2010 в 14:19
поделиться

2 ответа

Это всего лишь несколько тестовых примеров, которые люди должны наблюдать.

Работает

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 внутренней лямбды, даже если он указан явно. (?)

3
ответ дан 3 November 2019 в 08:20
поделиться

Природа '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
0
ответ дан 3 November 2019 в 08:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: