См. пример ниже. Не могу придумать причину, почему это невозможно. Действительно ли я вынужден использовать decl или typedef? Есть ли другие разумные обходные пути?
struct Foo {
public:
int get_res() { return 1; }
int get_res(int i) { return 1; }
};
// Works!
struct Accessor {
using overload = int(Foo::*)();
static constexpr overload resGetter = &Foo::get_res;
};
// error: expected unqualified-id before ')' token
struct Accessor {
static constexpr int(Foo::*)() resGetter = &Foo::get_res;
};
Синтаксис является остатком C, int(*resGetter)() — это бесплатная версия функции, и скобки, скорее всего, присутствуют, потому что в противном случае в общем случае невозможно отличить int*resGetter() от функции, возвращающей указатель на int, и, скорее всего, никто мог бы придумать, как заставить int() resGetter анализировать, не сломав что-то еще. Какими бы безумными ни выглядели вещи, для безумия всегда была веская причина. Даже если безумие возникло из-за ограничений инструментов и оборудования, доступных в 1970-х годах.
Очень полезная информация, если вы хотите продолжать копаться в этой кроличьей норе: isocpp.org/wiki/faq/pointers-to-members
У вас опечатка. Имя resGetter должно идти сразу после * в int(Foo::*)(). См. этот ответ в дураке: Как я могу определить член класса как указатель





struct Accessor2 {
static constexpr int(Foo::*resGetter)() = &Foo::get_res;
};
Вот почему вы обычно не пишете указатели на функции-члены таким образом — это выглядит странно, и люди делают ошибки.
Определения типов не генерируют никакого кода — вы можете использовать их столько, сколько хотите, чтобы ваш код был читабельным.
Спасибо, намерение состоит в том, чтобы использовать это в длинном наборе специализаций шаблонов, которые отображаются в заголовке, а псевдонимы в заголовках кажутся культовым грехом, который я не могу совершить.
«псевдонимы в заголовках кажутся культовым грехом» — ссылка обязательна
честно говоря, "псевдонимы в заголовках кажутся грехом карго-культа" звучит как карго-культ
«Никогда не объявляйте псевдонимы пространства имен или объявления удобного использования в области пространства имен в файлах заголовков, только в файлах .cc». И я бы отнес это к категории удобства. Откуда: «abseil.io/tips/…».
Все является грехом, если у вас нет веской причины этого не делать.
Возможно, большинство моих определений типов из заголовков находятся в классах, а не в пространствах имен, но в целом я бы не стал беспокоиться о каких-то правилах, которые кто-то придумал. Если это улучшает API, я делаю все, что работает.
@fyodor-the-ignorant, в статье, на которую вы ссылаетесь, не упоминаются псевдонимы типов. Речь идет об использовании объявлений для целых пространств имен и псевдонимов пространств имен. Хотя ссылка на руководство Google дает обоснование: «Как и другие объявления, псевдонимы, объявленные в файле заголовка, являются частью общедоступного API этого заголовка...», и если это то, что вы хотите, тогда сделайте это. Рекомендации Google касаются только того, чтобы не делать его частью общедоступного API, если он не должен быть частью общедоступного API. Я не согласен со многими пунктами руководства Google, но здорово, что в них представлены плюсы и минусы, чтобы вы могли принять решение.
@fyodor-the-ignorant, в руководстве Google даже есть положительные примеры, для которых они рекомендуют указывать это в заголовке.
Возвращаясь к этому: да, на самом деле соответствующая часть касалась того, что эти псевдонимы были объявлены как часть общедоступного API (google.github.io/styleguide/cppguide.html#Aliases). В моем случае эти псевдонимы являются исключительно внутренними деталями, и засорять общедоступный API именами, которые не должны использоваться клиентами, — это беспорядок, и на этом этапе у нас остаются только минусы.
Не заставляйте меня говорить о том, как это странно выглядит, но
static constexpr int(Foo::*resGetter)() = &Foo::get_res;