Смешивает ли старый и новый синтаксис функций С++ в допустимом классе?

Этот код действительно работает:

class Abstract {
    virtual auto foo() -> int = 0;
};

class Concrete: public Abstract {
    int foo() { cout << "blah!" << endl; return 1; }
} instance;

Я понимаю, что функция становится искаженной и привязана к одной и той же сигнатуре функции, но является ли это смешение фактически законным в С++ 14?

Ответ 1

auto foo()->int и int foo() - это один и тот же прототип, выраженный с различным синтаксисом, поэтому вторая функция является переопределением первого и будет заменять его в диспетчеризации (виртуальной) как обычно.

Синтаксис обратной ссылки справа, обычно имеет другую цель, например

template<class A, class B>
auto some_combination(A a, B b) -> decltype(a+b);

в противном случае требуется более сложный синтаксис, например

temlate<class A, class B>
decltype(std::declval<A>()+std::declval<B>()) some_combination(A a,B b);

так как a и b не определены в левой части прототипа.

Если тип возврата тривиально определен, левое или правое размещение по существу не имеет значения.

Ответ 2

Это законно, потому что на самом деле вы полностью определяете свою функцию.
Как минимальный рабочий пример (обратите внимание на override):

class Abstract {
    virtual auto foo() -> int = 0;
};

class Concrete: public Abstract {
    int foo() override { return 1; }
} instance;

int main() { }

Здесь тип возврата не выводится, он явно объявляется с помощью возвращаемого возвращаемого типа.
Это эквивалентно:

class Abstract {
    virtual int foo() = 0;
};

Было бы иначе, если вы использовали это:

class Abstract {
    virtual auto foo() = 0;
};

Здесь задействован вывод шаблона, и виртуальные функции не могут выводить возвращаемый тип (это более или менее строка ошибки из GCC).