Ошибка: инициализатор для гибкого члена массива 'const char* ArgumentGuard::_args []'

У меня есть этот класс, который я только что написал, см. ниже. Я пытаюсь создать утилиту class для проверки аргументов командной строки в параметрах argc и argvmain().

class ArgumentGuard {
public:
    ArgumentGuard() = default;
    ArgumentGuard(int& argc, char const *argv[]) : _arc{argc}, _args{*argv} {}

    bool has_arguments() const {
        return _arc < 2 ? false : true;
    }

private:
    int _arc;
    const char* _args[];
};

Использование:

int main(int argc, char const *argv[]) {
    ArgumentGuard guard(argc, argv);

Ошибка:

In constructor 'ArgumentGuard::ArgumentGuard(int&, const char**)':
 error: initializer for flexible array member 'const char* ArgumentGuard::_args []'
   60 |     ArgumentGuard(int& argc, char const *argv[]) : _arc{argc}, _args{*argv} {}
      |     ^~~~~~~~~~~~~~~~~~~
In file included from sectra.cpp:1:
 In constructor 'ArgumentGuard::ArgumentGuard(int&, const char**)':
 error: initializer for flexible array member 'const char* ArgumentGuard::_args []'
   60 |     SectraArgumentGuard(int& argc, char const *argv[]) : _arc{argc}, _args{*argv} {}
      |     ^~~~~~~~~~~~~~~~~~~
In constructor 'ArgumentGuard::ArgumentGuard(int&, const char**)':
error: initializer for flexible array member 'const char* ArgumentGuard::_args []'
   60 |     ArgumentGuard(int& argc, char const *argv[]) : _arc{argc}, _args{*argv} {}
      |     ^~~~~~~~~~~~~~~~~~~

Кстати: return _arc < 2 ? false : true; — это запутанный способ написания return _arc >= 2;.

Konrad Rudolph 10.06.2024 17:17
const char* _args[] недействителен в С++. См. CASE 4 в ответе на странице Является ли int arr[ ] допустимым для C++?
user12002570 10.06.2024 17:17

Гибкие члены массива не являются функцией C++, это расширение вашего компилятора. Если вам нужны ответы здесь, вам следует упомянуть компилятор и его версию. На данный момент дубликат верен, имея только тег c++, мы можем сделать вывод, что вы хотите написать код в соответствии со стандартом C++, если вы отредактируете вопрос, я смогу снять замыкание.

Yksisarvinen 10.06.2024 17:20

Хотя дубликат действительно объясняет ошибку, я не думаю, что он отражает то, что на самом деле пытался сделать этот спрашивающий. Измените const char* _args[]; на const char** _args; и измените _args{*argv} на _args{argv}.

Drew Dormann 10.06.2024 17:26

@DrewDormann Им может понадобиться член гибкого массива, откуда вы знаете, что это не должно быть так?

Yksisarvinen 10.06.2024 17:36

Связанный материал: Допустимы ли члены гибкого массива в C++?

Remy Lebeau 10.06.2024 17:39

@Yksisarvinen Я основывал это предположение на том, что «я пытаюсь создать служебный класс для проверки аргументов командной строки в параметрах argc и argv функции main().». Это не похоже на работу с гибкими массивами.

Drew Dormann 10.06.2024 17:55
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
7
84
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Синтаксис массивов в стиле C может быть сложным.

Параметр функции, такой как ваш char const *argv[], на самом деле не является массивом — это сокращение указателя. Это то же самое, что char const **argv.

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

class ArgumentGuard {
public:
    ArgumentGuard() = default;
    ArgumentGuard(int argc, char const *argv[]) : _arc{argc}, _args(argv) {}

    bool has_arguments() const {
        return _arc < 2 ? false : true;
    }

private:
    int _arc;
    const char** _args;
};

Кроме того, нет смысла передавать argc по ссылке только для того, чтобы скопировать его значение. Передайте его по значению, а не по ссылке.

Remy Lebeau 10.06.2024 17:36

Дрю, спасибо. Я решил использовать std::vector<T> ;-)

Alix Blaine 10.06.2024 17:47

Помимо того, что VLA не является стандартным расширением, инкапсуляция ссылки (int&) внутри класса создает проблемы на протяжении всего срока службы, что приводит к зависанию. В общем, оба члена вашего ArgumentGuard неприятны.

Я приглашаю вас воспользоваться преимуществами современного C++ вместо того, чтобы пробовать сложные вещи и необработанные указатели. Аргументы командной строки — еще одно приложение для C++20 <ranges>:

#include <ranges>
int main(int argc, char const ** argv){
    using namespace std::views; //counted, transform, as_const
    auto args = counted(argv, std::size_t{argc})
              | transform([](auto s){ return std::string_view{s}; })
              | as_const;

   auto args_guard = [args]
   { return std::ranges::size(args) >= 2; };
   if (not args_guard())
       return ~0;
   //Blah blah
   return 0;
};

В приведенном выше фрагменте args — это толстый указатель на аргументы командной строки, которые можно передавать по значению — если только не в отдельный поток. Он занимает мало памяти в автоматическом режиме и не вызывает динамического выделения. Каждый аргумент командной строки рассматривается как std::string_view. Таким образом, единственным случаем явного использования указателя теперь является неизбежная инициализация из argv. Этот фрагмент обеспечивает большую безопасность при абсолютно нулевых затратах.

Это отличное и современное решение, хотя я не согласен с тем, что инициализация std::string_view из каждого const char* имеет «абсолютную нулевую стоимость». Это единственный код, который перебирает каждый символ.

Drew Dormann 11.06.2024 15:19

Преобразование @DrewDormann в string_view — единственный вариант, который предотвращает использование необработанных строковых указателей. Затраты на вычисление длины компенсируются, когда объект string_view используется в выражении. Обычно он объединяется внутри функции форматирования.

Red.Wave 11.06.2024 15:25

Более того, преобразование происходит только при доступе к элементам. Поэтому я делаю ставку на его производительность по сравнению с любым другим конкурентом.

Red.Wave 11.06.2024 15:31

Другие вопросы по теме