Я читал чужой код, в котором были пользовательские классы функций, похожие на boost::function или std::function. Они передавали эти классы функций по постоянной ссылке. В одном разделе, посвященном критическому пути, они решили вместо этого использовать указатели на функции, но по-прежнему посредством постоянной ссылки с комментариями о большей эффективности.
В их коде был эквивалент этого:
using FuncT = int(*)(int, int);
Что передавалось так:
const FuncT&
Я предполагаю, что const FuncT& на самом деле не более эффективно передавать, чем FuncT, и что синтаксис просто остался от того, что изначально был их пользовательским классом функции. Однако это заставило меня задуматься о значении const FuncT.
#include <iostream>
using FuncT = int(*)(int, int);
struct MyClass final {
static int myMethod(int a_arg1, int a_arg2) {
std::cout << a_arg1 << " " << a_arg2 << std::endl;
return 0;
}
// Similar to what I found in someone's code
void v1(const FuncT& a_func) { a_func(1, 1); }
// A reference to a const function pointer seems meaningless, it should be
// just as efficient to copy the pointer
void v2(const FuncT a_func) { a_func(2, 2); }
// ^
// Removed reference
// I believe this is the syntax for a function pointer that cannot be
// modified to point to a different function
void v3( int(* const a_func)(int, int)) { a_func(3, 3); }
// ^
// Added const not present in FuncT
// This compiles but I don't know what the intended meaning of the extra
// const would be
void v4(const int(* const a_func)(int, int)) { a_func(4, 4); }
// ^
// Added const not present in v3
};
int main() {
MyClass myClass;
myClass.v1(&MyClass::myMethod);
myClass.v2(&MyClass::myMethod);
myClass.v3(&MyClass::myMethod);
//myClass.v4(&MyClass::myMethod); // Doesn't compile
return 0;
}
В приведенном выше коде v4 компилируется, но каково предполагаемое значение самого левого const?
Кстати, ваш комментарий к версии 3 верен.
@john, мне тоже это интересно, но использование v2 (const FuncT) компилируется, а использование v4 нет
@asimes В вопросе вы сказали, что v4 компилируется.
@john, я имел в виду использование внутри main
Хорошо, запомните то, что я сказал: указатели v3 и v4 — это не одно и то же. Константность типа возвращаемого значения функции имеет значение.
Однако константа верхнего уровня удалена из параметров функции, возможно, я об этом и думал.
Поможет ли вам мой вопрос: Что означает указатель на константную функцию
@ThomasMatthews Это похоже, но в конечном итоге я узнал, что const FuncT эквивалентно int(* const)(int, int), а не эквивалентно const int(*)(int, int), что изначально показалось мне нелогичным





Незначительные изменения в вашем коде:
void v3( int(* const a_func)(int, int)) {
a_func = &MyClass::myMethod; // no, a_func is const
}
a_func — const вы не можете его изменить. Попытка назначить ему вызывает ошибку.
Здесь:
void v4(const int(* const a_func)(int, int)) { a_func(4, 4); }
// |-------|
то же, что и выше, но тип возвращаемого значения функции — const int, а не int:
const int foo(int,int) { return 42;}
int main() {
MyClass myClass;
myClass.v4(&foo);
}
Что меня до сих пор смущает, так это то, почему
const FuncTне эквивалентно аргументуv4.
Грамматика указателей на функции странная, поэтому мы используем псевдонимы как можно чаще. Для подробного объяснения я отсылаю вас к соответствующей литературе. В данном случае это просто returntype (* outer_most_const)(parameter_types), а с псевдонимом using f = returntype (*)(parameter_types) вы добавляете самую внешнюю константу через const f.
Это меня удивляет, потому что я думал, что не будет никакой разницы в возврате int и const int, поскольку компилятор знает, что в обоих случаях он просто копирует int. Что меня до сих пор смущает, так это то, почему const FuncT не эквивалентно аргументу v4.
@asimes для int разница не имеет значения. Но если учесть, что он вернет объект Bar, тогда foo(1,2) = some_bar_object; является ошибкой только потому, что foo возвращает константу. Раньше рекомендовалось возвращать const объекты, чтобы предотвратить случайное назначение или иное изменение временных объектов. Эта рекомендация устарела после семантики перемещения.
Например, @asimes godbolt.org/z/5Wvj1q1hc
Спасибо, теперь я понял, и вы ответили на вопрос. Однако у меня все еще есть одно сомнение: почему аргумент v4 не эквивалентен аргументу const FuncT
@asimes см. редактирование. В const FuncTconst — это самая внешняя константа, т. е. она применяется к самому объекту. В декларации указателя функции «самая внешняя константа» находится где-то посередине.
@asimes, кстати, иногда это очень полезно. Он предназначен для C, поэтому не знает всего C++, но работает для указателей функций cdecl.org/?q=const+int%28*+const+a_func%29%28int%2C+int%29%3 Б
@asimes это также работает и наоборот cdecl.org/… =)
Это означает, что функция возвращает
const int. Не цитируйте меня, но я считаю, чтоconstигнорируется в типе указателя функции, поэтому v3 и v4 на самом деле одинаковы.