Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::visit for QObject's

I have the following code that does not compile with Qt 6.7.2 on Debian :

#include <QCoreApplication>

#include <iostream>    
#include <variant>

class Foo : public QObject
{
    Q_OBJECT
};

class Bar : public QObject
{
    Q_OBJECT
};

struct Vis
{
    void operator()(const Foo &f)
    {
        std::cout << "foo visitor" << std::endl;
    }
    void operator()(const Bar &b)
    {
        std::cout << "bar visitor" << std::endl;
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    std::variant<Bar, Foo> v;
    Foo f;
    Bar b;

    v = b;
    std::visit(Vis{}, v);
    v = f;
    std::visit(Vis{}, v);

    return a.exec();
}

#include "main.moc"

The error is :

error: no match for ‘operator=’ (operand types are ‘std::variant<Bar, Foo>’ and ‘Bar’)
v = b;

As a workaround it seems ok to use raw pointers to QObject's instead :

struct Vis
{
    void operator()(const Foo *f)
    {
        std::cout << "foo visitor" << std::endl;
    }
    void operator()(const Bar *b)
    {
        std::cout << "bar visitor" << std::endl;
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    std::variant<Bar *, Foo *> v;
    Foo *f;
    Bar *b;

    v = b;
    std::visit(Vis{}, v);
    v = f;
    std::visit(Vis{}, v);

    return a.exec();
}

Am i missing something to store a QObject derived class inside a std::variant?

like image 780
Fryz Avatar asked Dec 21 '25 06:12

Fryz


1 Answers

QObject has no assignment, hence neither Foo nor Bar have an assignment operator. For the reasons I refer you to https://doc.qt.io/qt-5/object.html#identity-vs-value. This would fail with similar eror for the same reason:

Foo f;
Foo g;
f = g;

As Foo and Bar already share a common base you can make use of polymorphism. Rather than using std::visit use virtual functions:

struct foobarable { 
    virtual ~foobarable() {}
    virtual void foobar() = 0; 
};

class Foo : public QObject,foobarable
{
    Q_OBJECT
    void foobar() override { std::cout << "foo" << std::endl; }
};

class Bar : public QObject,foobarable
{
    Q_OBJECT
    void foobar() override { std::cout << "bar" << std::endl; }
};

As mentioned in a comment, if you really want to use std::variant<Foo,Bar> a workaround would be to use emplace to construct the instance in place:

std::variant<Bar, Foo> v;
v.emplace<Bar>();
std::visit(Vis{}, v);
v.emplace<Foo>();
std::visit(Vis{}, v);

Full example

like image 99
463035818_is_not_a_number Avatar answered Dec 23 '25 19:12

463035818_is_not_a_number