Объявление функции-члена с использованием синтаксиса типа функции
Совсем недавно я узнал, что вы можете объявить функцию (включая методы), используя переменный синтаксис с типом функции:
using function_type = int (double);
// pre-C++11:
//typedef int function_type(double);
function_type fun_global;
struct methods
{
static function_type mem_fun_static;
function_type mem_fun_normal;
virtual function_type mem_fun_virtual;
virtual function_type mem_fun_abstract = 0;
};
В приведенном выше коде
fun_global
это глобальная функция,mem_fun_static
этоstatic
функция-член,mem_fun_normal
это обычный метод,mem_fun_virtual
этоvirtual
метод,mem_fun_abstract
это абстрактный метод.
Все они принимают один аргумент типа double
и вернуться int
значение - так же, как function_type
говорит.
Все эти годы я знал C++ и не знал об этом - этот язык не перестает меня удивлять! Кстати - этот синтаксис упоминается где-нибудь здесь? Я не вижу этого...
Однако, исследуя эту новую для меня функцию, я наткнулся на некоторые несоответствия между компиляторами. Для тестов я использовал следующие компиляторы:
- GCC 5.4.0 и 7.1.0, командная строка:
g++ -Wall -Wextra -pedantic -std=c++14
- Clang 4.0.1, командная строка:
clang++ -Wall -Wextra -pedantic -std=c++14
- MSVC 19.10.25019 (VS 2017), командная строка:
cl /W4 /EHsc
В тестах, которые я запускаю, обе версии GCC дали один и тот же результат, поэтому в дальнейшем я называю их GCC.
= delete
несогласованность
struct methods
{
/* ... */
function_type mem_fun_deleted = delete;
};
- GCC: ОК
Лязг: ошибка!
Test.cpp:13:34: error: '= delete' is a function definition and must occur in a standalone declaration function_type mem_fun_deleted = delete; ^ 1 error generated.
MSVC: хорошо
= default
несогласованность
struct methods
{
/* ... */
using assignment_type = methods& (methods const&);
assignment_type operator= = default;
};
- GCC: ОК
Лязг: ошибка!
Test.cpp:14:30: error: '= default' is a function definition and must occur in a standalone declaration assignment_type operator= = default; ^ 1 error generated.
MSVC: ошибка!
Test.cpp(14): error C2206: 'methods::operator =': typedef cannot be used for function definition
Несовместимость встроенного определения
struct methods
{
/* ... */
function_type mem_fun_inline { return 0; }
};
GCC: ошибка!
Test.cpp:13:43: error: invalid initializer for member function ‘int methods::mem_fun_inline(double)’ function_type mem_fun_inline { return 0; } ^ Test.cpp:13:43: error: expected ‘;’ at end of member declaration
Лязг: ошибка!
Test.cpp:13:33: error: expected expression function_type mem_fun_inline { return 0; } ^ Test.cpp:7:8: error: missing '}' at end of definition of 'methods' struct methods ^ /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/x86_64-pc-cygwin/bits/c++config.h:194:1: note: still within definition of 'methods' here namespace std ^ 2 errors generated.
MSVC: хорошо
Вопросы
Какие компиляторы здесь?
Кроме того, возможно ли:
- Во встроенном определении (поддерживается только MSVC) ссылаться как-то на аргумент?
Каким-то образом использовать
function_type
также при определении этих функций (когда выполняется вне класса). Следующее в порядке (со всеми компиляторами)struct methods { static function_type mem_fun_static; /* ... */ }; int methods::mem_fun_static(double) { return 0; }
Это не так плохо, так как смена
function_type
должен привести к ошибке компиляции при определении функции (так как она больше не будет соответствовать объявлению) - но все же, возможно, можно избежать даже этого.
1 ответ
§ 8.3.5 Функции [dcl.fct] p12 Определение типа функции может использоваться для объявления функции, но не должно использоваться для определения функции.
Таким образом, Clang вправе отклонить код во всех случаях, а компиляторы, которые его принимают, ошибаются.
(Цитата из N4618, но правило является частью языка с незапамятных времен).