Могу ли я использовать первый параметр шаблона по умолчанию?

У меня есть метод шаблона с двумя параметрами имени типа (на самом деле это QObject::connect() - см. этот ответ и другой ответ). Поскольку имена типов предназначены для указателей на элементы, дедукция может завершиться ошибкой, если переданное имя ссылается на перегруженную функцию; когда это происходит, нам нужно либо привести один аргумент к правильному типу (возможно, сохранив его в локальной переменной нужного типа), либо квалифицировать вызов с помощью одного или нескольких параметров шаблона.

Взяв пример из одного из связанных вопросов:

QObject::connect(spinBox, &QSpinBox::valueChanged,
                 slider, &QSlider::setValue);

нужно записать как

QObject::connect<void(QSpinBox::*)(int)>(spinBox, &QSpinBox::valueChanged,
                                         slider, &QSlider::setValue);

или (по принуждению):

void(QSpinBox::*signal)(int) = &QSpinBox::valueChanged;
QObject::connect(spinBox, signal,
                 slider, &QSlider::setValue);

Однако иногда можно вывести первый аргумент шаблона, но требуется более поздний. Есть ли простой способ установить первый параметр по умолчанию, но указать другие? Я думал о чем-то вроде

QObject::connect<auto, void(QSpinBox::*)(int)>(slider, &QSlider::valueChanged,
                                               spinBox, &QSpinBox::setValue);

Очевидно, что это недопустимый C++, но я надеюсь, что это иллюстрирует суть.

Я знаю, что могу написать

void(QSpinBox::*slot)(int) = &QSpinBox::setValue;
QObject::connect(slider, &QSlider::valueChanged,
                 spinBox, slot);

но я надеюсь на более краткий синтаксис.


person Toby Speight    schedule 04.10.2016    source источник
comment
Я думаю, вы должны иметь возможность преобразовать функцию в тип указателя, который вы хотите, с помощью статического приведения. Что-то вроде static_cast<void(QSpinBox::*)(int)>(QSpinBox::setValue). Это должно позволить работать выводу аргументов шаблона, поэтому вам не нужно указывать тип.   -  person NathanOliver    schedule 04.10.2016
comment
Что ж, это даже уродливее — я предпочитаю определять разумный up_cast<>(), который безопаснее (и также полезен для принуждения аргументов ?: без сужения).   -  person Toby Speight    schedule 04.10.2016


Ответы (1)


Есть ли простой способ установить первый параметр по умолчанию, но указать другие?

Нет. Вам просто нужно указать второй аргумент вручную, например, с static_cast:

QObject::connect(slider, &QSlider::valueChanged,
    spinBox, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::setValue));

Или просто используйте другую перегрузку connect() и передайте лямбду:

QObject::connect(slider, &QSlider::valueChanged,
    [&spinBox](int i){ spinBox.setValue(i); });
person Barry    schedule 04.10.2016
comment
Я подозревал, что ответ, скорее всего, будет «нет», но, похоже, стоило спросить. Тогда я буду придерживаться подхода с локальной переменной как самого чистого. - person Toby Speight; 04.10.2016
comment
@TobySpeight Не поклонник лямбда-подхода? - person Barry; 04.10.2016
comment
Не особенно, но это субъективно. Я бы не возражал против этого в код-ревью, но и сам редко писал бы. Вероятно, я представляю себе гораздо больше накладных расходов, чем на самом деле несут такие лямбды! Здесь вам нужно быть осторожным, так как вы слегка изменили аргумент типа соединения с «авто» на «прямое» — это не проблема в соединениях UI->UI, таких как это, но может быть проблематичным при межпотоковом соединении. - person Toby Speight; 04.10.2016