Search code examples
c++templatestemplate-argument-deduction

Can I default the first template parameter?


I have a template method with two typename parameters (it's actually QObject::connect() - see this answer and another answer). Because the typenames are for member pointers, deduction can fail when the name passed in refers to an overloaded function; when that happens, we need to either coerce one argument to the correct type (perhaps by storing it into a local variable of the desired type) or to qualify the call with one or more of the template parameters.

Taking an example from a one of the linked questions:

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

needs to be written as

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

or (by coercing):

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

Sometimes, though, the first template argument could be deduced, but a later one is required. Is there an easy way to default the first parameter, but specify others? I was thinking of something like

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

Obviously, that's not valid C++, but I hope it illustrates the point.

I know I can write

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

but I'm hoping for a more concise syntax.


Solution

  • Is there an easy way to default the first parameter, but specify others?

    No. You'll just have to coerce the second argument manually, like with a static_cast:

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

    Or just use a different overload of connect() and pass a lambda:

    QObject::connect(slider, &QSlider::valueChanged,
        [&spinBox](int i){ spinBox.setValue(i); });