LINUX.ORG.RU

[Qt] Как написать для QMap значение по-умолчанию в прототипе функции?

 


0

2

Здравствуйте!


Есть функция, которой может последним параметром передаваться QMap. А может и не передаваться.

Вопрос - как в прототипе такой функции прописать значение по-умолчанию для QMap?

Пробовал так:

void function( QString name, QMap<QString, QStringList> record=QMap<QString, QStringList>() )
{
 ...
}

Компиляция не идет, выдает ошибку:

src/recordtabledata.h:53: error: expected ‘,’ or ‘...’ before ‘>’ token
src/recordtabledata.h:53: error: wrong number of template arguments (1, should be 2)

Как сделать правильно?


Ответ на: комментарий от antony986

> а если сделать typedef на это дело?

Попробовал и так и сяк, не выходит.

Я вот думаю, чего это я задаю в качестве значения по-умолчанию значение конструктора QMap(), так же нельзя. Должна быть какая-то константа вроде.

А как для QMap константу сделать?

xintrea
() автор топика
#include <QApplication>
#include <QDebug>
#include <QMap>
#include <QStringList>

void function(QString name, QMap<QString, QStringList> record = QMap<QString, QStringList>()) {
    qDebug() << name << record;
}

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    function("name");
    return 0;
}

Собирается и работает.

rival ★★
()
Ответ на: комментарий от xintrea

чего это я задаю в качестве значения по-умолчанию значение конструктора QMap(), так же нельзя

вообще-то именно так и делается, не парься :)

wmd
()
Ответ на: комментарий от xintrea

>>Я вот думаю, чего это я задаю в качестве значения по-умолчанию значение конструктора QMap(), так же нельзя

Почему нельзя?

alex_custov ★★★★★
()
Ответ на: комментарий от rival

> Собирается и работает.

Да, действительно. У меня тоже ваш пример собрался на ура.

И точно такой же синтаксис не хочет работать в моем коде:

http://rghost.ru/3138962/image.png

Причем в начале этого файла прописано

#include <QMap>
#include <QString>
#include <QByteArray>


xintrea
() автор топика
Ответ на: комментарий от xintrea

Запости минимальный нерабочий код. Может у тебя там в каком-то из h'ников делается #define QByteArray %уй а нам этого не видно

Reset ★★★★★
()
Ответ на: комментарий от rival

Да, в моей функции компилятору плохеет.

У меня 9 параметров, и заканчивается на типе QMap<QString, QByteArray>.

А компилятор видит 10 параметров, и добавляет лишний QByteArray:

src/recordtabledata.h:59: error: default argument missing for parameter 10 of ‘int recordtabledata::insert_new_record(int, int, QString, QString, QString, QString, QString, QString, QMap<QString, QByteArray>, QByteArray)’

Щас попробую еще раз с typedef поиграться. Но всеравно очень странно, почему такого эффекта в вашем примере не наблюдается.

xintrea
() автор топика
Ответ на: комментарий от xintrea

Потому что для предпоследнего вы указали значение по-умолчанию, а для последнего - нет. C++, матчасть.

Dendy ★★★★★
()
Ответ на: комментарий от Reset

> Запости минимальный нерабочий код. Может у тебя там в каком-то из h'ников делается #define QByteArray %уй а нам этого не видно

Ну я такого изврата точно не делал.

Проблема в том, что вот щас пытаюсь сделать минимальный нерабочий код - он сука работает. А в проекте - хуй.

xintrea
() автор топика
Ответ на: комментарий от xintrea

У тебя точно там нигде не завалялся второй файл с названием recordtabledata.h?

rival ★★
()
Ответ на: комментарий от Dendy

> Потому что для предпоследнего вы указали значение по-умолчанию, а для последнего - нет. C++, матчасть.

Где вы увидели у предпоследнего аргумента значение по-умолчанию? У меня только на последнем по-умолчанию сделано.

xintrea
() автор топика
Ответ на: комментарий от rival

> На скриншоте там 9 аргументов и заканчивается QMap'ом, а не QByteArray'ем.

Вот именно, а компилятор видит 10 параметров.

Я с таким уже встречался: http://www.prog.org.ru/topic_15278_0.html

Но что-то сейчас даже typedef не помогает.

xintrea
() автор топика
Ответ на: комментарий от xintrea

> Где вы увидели у предпоследнего аргумента значение по-умолчанию?

Посчитал:

src/recordtabledata.h:59: error: default argument missing for parameter 10 of ‘int recordtabledata::insert_new_record(int, int, QString, QString, QString, QString, QString, QString, QMap<QString, QByteArray>, QByteArray)’


QMap - это девять.
QByteArray - это десять.

Dendy ★★★★★
()
Ответ на: комментарий от xintrea

Я подумал вы дописали ещё один аргумент сами. Какая версия компилятора? Может попробовать собрать более новым GCC?

Dendy ★★★★★
()
Ответ на: комментарий от xintrea
#include <QString>
#include <QMap>
#include <QByteArray>

class A
{
public:
    int insert_new_record(int, int, QString, QString, QString, QString, QString, QString, QMap<QString, QByteArray> r = QMap<QString, QByteArray>());
};

int A::insert_new_record(int, int, QString, QString, QString, QString, QString, QString, QMap<QString, QByteArray>)
{
    return 5;
}

int main( int argc, char ** argv )
{
    A a;
    return a.insert_new_record(1, 2, "a", "b", "c", "d", "e", "f", QMap<QString, QByteArray>());
}
dendy@dendy:~/projects/tmp/10args/build> make
[100%] Building CXX object CMakeFiles/a.dir/main.o
Linking CXX executable a
[100%] Built target a
dendy@dendy:~/projects/tmp/10args/build>  

$ g++ --version
g++ (SUSE Linux) 4.5.0 20100604 [gcc-4_5-branch revision 160292]

Dendy ★★★★★
()
Ответ на: комментарий от rival

Фух, закомпилилось, вот с таким прототипом:

 void add_new(int mode,
              QString name,
              QString author,
              QString url,
              QString tags,
              QString text,
              QString images_directory,
              QMap<QString, QByteArray> files=(QMap<QString, QByteArray>()) );

Если вместо

QMap<QString, QByteArray> files=(QMap<QString, QByteArray>())

написать

QMap<QString, QByteArray> files=QMap<QString, QByteArray>()

То вылазят ошибки.

При этом копия этой функции в минимальном примере нормально компилится без дополнительных скобочек!

...

Такс, походу нащупал. В упрощенном примере нормальная компиляция без дополнительных скобочек идет только в том случае, если функция - это обычная функция, а не метод класса.

Если сделать из функции метод класса - то вылазит такая ошибка как у меня.

Пример: http://rghost.ru/3139469

xintrea
() автор топика
void function( QString name, QMap<QString, QStringList> record=QMap<QString, QStringList>() )

1. не стоит использовать значения по умолчанию, да ещё в таком страшном виде

2. чего бы не сделать вот так:

void function( QString name, QMap<QString, QStringList> *record) {
    if(!record) {
        record = new ....
    }

    ....
}

гораздо понятнее ИМХО

shty ★★★★★
()
Ответ на: комментарий от Dendy

> Какая версия компилятора? Может попробовать собрать более новым GCC?

Попробуйте, пожалуйста собрать мой пример из поста выше.

У меня он не собирается, пока не допишу скобочки вокруг дефолтного значения.

xintrea
() автор топика
Ответ на: комментарий от Gorthauer

Gorthauer (фотография)

А мне мама говорила, что нежелательно делать функции с таким числом аргументов.

плюсую, как минимум вот это

              QString name,
              QString author,
              QString url,
              QString tags,
              QString text,

легко и логически понятно собирается в структуру

shty ★★★★★
()
Ответ на: комментарий от Gorthauer

> А мне мама говорила, что нежелательно делать функции с таким числом аргументов.

Знаю, но не могу придумать как представить/формализовать аргументы в данном случае. Я могу конечно набор QString передать как хеш, но хочу видеть в прототипе, что у меня передается.

xintrea
() автор топика
Ответ на: комментарий от shty

Хотя да в структуру тоже можно, будет правильней.

xintrea
() автор топика
Ответ на: комментарий от xintrea

> Попробуйте, пожалуйста собрать мой пример из поста выше.

И функция и метод компилируются как со скобочками, так и без них.

Dendy ★★★★★
()
Ответ на: комментарий от xintrea

Если вместо
QMap<QString, QByteArray> files=(QMap<QString, QByteArray>())
написать
QMap<QString, QByteArray> files=QMap<QString, QByteArray>()
То вылазят ошибки.

Жестоко. Парсер - лох!

rival ★★
()
Ответ на: комментарий от Dendy

> И функция и метод компилируются как со скобочками, так и без них.

Во как. Значит, мне «повезло» с версией gcc.

gcc (Debian 4.3.2-1.1) 4.3.2

xintrea
() автор топика
Ответ на: комментарий от shty

> каким образом?

Ну, например, можно забыть проследить за освобождением памяти.
Кроме того, ты в своей функции выделяешь память в случае, если аргумент равен нулю, что означает, что либо ты должен как-то вернуть указатель на эту выделенную память, либо освободить ее там же. А еще пользователю нужно знать и помнить, освобождает ли память твоя функция или это должен делать или не делать пользователь. А если освобождает, то устраивает ли это пользователя? Лишние сложности.
А что будет, если во время исполнения функции кто-то будет производить манипуляции с данными по этому указателю?
Это всё как минимум говорит о том, что твой вариант не эквивалентен первоначальному.

А вообще, ты можешь всё списать на то, что я просто не люблю указатели. =)

rival ★★
()
Ответ на: комментарий от shty

void function(const QString& name, ...

это, кстати, не всегда хорошо

если используются треды, то надо передавать по значению

wmd
()
Ответ на: комментарий от rival

каким образом?

поддерживаю

Ну, например, можно забыть проследить за освобождением памяти.

бред не пишите

вы посмотрите в свой же код, где вы там QMap через new создаете?

anonymous2 ★★★★★
()
Ответ на: комментарий от rival

А вообще, ты можешь всё списать на то, что я просто не люблю указатели. =)

а большинство вменяемых людей напрягают конструкторы копирования в параметрах функций, QMap<QString, QStringList> ага

anonymous2 ★★★★★
()
Ответ на: комментарий от anonymous2

>> Ну, например, можно забыть проследить за освобождением памяти.
бред не пишите

Что, нельзя забыть? В чем бред-то заключается?

вы посмотрите в свой же код, где вы там QMap через new создаете?

Причем тут мой код? Вот же:

    if(!record) {
        record = new ....
    }

rival ★★
()
Ответ на: комментарий от anonymous2

> а большинство вменяемых людей

«Всем известно, что ...», ага.

rival ★★
()
Ответ на: комментарий от xintrea

прогони свой исходник через препроцессор и посмотри во что превращается функция

Reset ★★★★★
()
Ответ на: комментарий от anonymous2

а большинство вменяемых людей напрягают конструкторы копирования в параметрах функций, QMap<QString, QStringList> ага

зачем напрягать конструкторы копий при передаче параметров другое дело возвращаемое значение тогда да удобно вернуть по значению чтоб не освобождать возвращенную память можно конечно вернуть умный указатель и тоже не думать про удаление

osox
()
Ответ на: комментарий от rival

> каким образом?

Ну, например, можно забыть проследить за освобождением памяти.

не, это лучше тогда сразу писать на языках с GC, проблема там может быть в другом - в прерывании работы до достижения сборки памяти, например вылетает левый exception и всё - потекло

Кроме того, ты в своей функции выделяешь память в случае, если аргумент равен нулю, что означает, что либо ты должен как-то вернуть указатель на эту выделенную память, либо освободить ее там же. А еще пользователю нужно знать и помнить, освобождает ли память твоя функция или это должен делать или не делать пользователь. А если освобождает, то устраивает ли это пользователя? Лишние сложности.

не совсем так, если передан NULL в функцию - то создастся объект-заглушка, который всё нормально отработает и будет удалён при выходе, если передан ненулевой указатель - всё отработает без удаления, таким образом пользователь получает требуемое поведение и ни о чём не заботится

однако мне это всё очень не нравится, уж больно подозрительно пахнет такой код

А что будет, если во время исполнения функции кто-то будет производить манипуляции с данными по этому указателю?

а для этого у нас есть ракетница, багор и ведро с песком (с) то есть различные виды синхронизации

Это всё как минимум говорит о том, что твой вариант не эквивалентен первоначальному.

эквивалентен, эквивалентен, только немного концентрируется на недостатках данного подхода

ещё раз: считаю что использования параметров по умолчанию следует избегать, и товарищи из google тоже так считают и я с ними согласен

shty ★★★★★
()
Ответ на: комментарий от wmd

> void function(const QString& name, ...

это, кстати, не всегда хорошо

если используются треды, то надо передавать по значению

простите, но то аргумент из серии: если бы у бабушки был...

1) то что где-то могут быть треды совсем не означает что каждый раз при вызове метода надо копировать данные

2) «если используются треды, то надо передавать по значению» сам факт наличия тредов не устанавливает по умолчанию правила передачи параметров функций по значению, надо смотреть конкретную ситуацию

shty ★★★★★
()
Ответ на: комментарий от shty

> каким образом?

Ну, например, можно забыть проследить за освобождением памяти.

не, это лучше тогда сразу писать на языках с GC, проблема там может быть в другом - в прерывании работы до достижения сборки памяти, например вылетает левый exception и всё - потекло

и да, как тут правильно заметили проблема легко решается использованием smart pointers

shty ★★★★★
()
Ответ на: комментарий от shty

нормальный это аргумент, такие вещи всегда полезно в уме держать

1) при передаче QString по значению ничего не копируется, у нее вообще размер как у указателя, так что может даже и оптимальнее будет по значению передавать

2) не спорю, мне просто лень было расписывать в подробностях

wmd
()
Ответ на: комментарий от shty

а для этого у нас есть ракетница, багор и ведро с песком (с) то есть различные виды синхронизации

Да, но в первоначальном варианте этого не требовалось, тогда о какой эквивалентности идет речь тут:

эквивалентен, эквивалентен, только немного концентрируется на недостатках данного подхода


ещё раз: считаю что использования параметров по умолчанию следует избегать, и товарищи из google тоже так считают и я с ними согласен

Может быть, но ведь ты не избавился от параметра по умолчанию, ты только придумал костыль для не понравившегося тебе и глючному компилятору синтаксиса, который вдобавок меняет поведение функции. И я все еще не пойму чем он, костыль, лучше-то?

rival ★★
()
Ответ на: комментарий от wmd

нормальный это аргумент, такие вещи всегда полезно в уме держать

не согласен, если Вам априори известно что параллельное исполнение не нужно - нафига усложнять задачу?

1) при передаче QString по значению ничего не копируется

это как, не поясните?

shty ★★★★★
()
Ответ на: комментарий от rival

а для этого у нас есть ракетница, багор и ведро с песком (с) то есть различные виды синхронизации

Да, но в первоначальном варианте этого не требовалось, тогда о какой эквивалентности идет речь тут: Цитата

эквивалентен, эквивалентен, только немного концентрируется на недостатках данного подхода

как только Вы осознаете тот факт что в первоначальной задаче ничего про потоки сказано не было Вам станет сразу легче

shty ★★★★★
()
Ответ на: комментарий от rival

ты не избавился от параметра по умолчанию

найдёте хоть один?

void function(QString name, QMap<QString, QStringList> *record)

глючному компилятору синтаксиса

ога, ога, какому там программисту и компилятор работать мешает?

И я все еще не пойму чем он, костыль, лучше-то?

поясняю: одна из проблем состоит в ожиданиях человека пишущего код, если говорить точнее то в непрогнозируемом поведении функции, то есть человек совсем не ожидает, что если не указывается второй параметр то при вызове функции там где-то на заднем плане вызывается «всего лишь» 3 конструктора

между вариантами:

1) function(some_name);
2) function(some_name, NULL);

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

ну и до кучи можете почитать что там гугловцы по этой теме пишут

если этим начать злоупотреблять то потом замучишься отлаживать такой код (автоматическое тестирование пока опустим)

shty ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.