Home > Mobile >  C prevent ambiguous parameter int vs int&
C prevent ambiguous parameter int vs int&

Time:11-08

I specalized QApplication as MyApplication taking an int parameter for construction.

class MyApplication : public QApplication
{
public:
    Foo( int argc, char **argv ) : QApplication( argc, argv )
    {
        ...
    }
};

This class is again specialized in many places in my code.

Unfortunately, I used int, while I should have used int& (as Qapplication expects). Under Windows it did not cause any trouble, but when I moved to Linux it started crashing. So I changed MyApplication to:

class MyApplication : public QApplication
{
public:
    Foo( int& argc, char **argv ) : QApplication( argc, argv )
    {
        ...
    }
};

But then, all classes specializing MyApplication also need to be updated, and there are many of them, if they are not, code still compiles but is likely to crash.

I need to identify all places where the change should be applied, but I also want to prevent new code from doing the same mistake.

Is there any way/trick to prevent specialization with int instead of `int&' to compile?

I'd like this code not to be permitted and to produce compilation error:

class OtherApplication : public MyApplication 
{
public:
    Foo( int argc, char **argv ) : MyApplication( argc, argv )
    {
        ...
    }
};

CodePudding user response:

To summarize your question: you need to make a change to a signature of a function (in this case a constructor) and everywhere it is used it's necessary to make a corresponding change, of some sort, but the signature change won't always result in a compilation failure every time, that you can pull up and fix, and move to the next one.

The solution is to have a guaranteed compilation failure:

MyApplication( int &argc, char **argv, int ignore ) : QApplication( argc, argv )

Now you're guaranteed to have a compilation failure due to a missing parameter.

As part of fixing every guaranteed compilation failure you'll also add a dummy 0 parameter.

Once all compilation failures get fixed, and the code compiles, you're now going to go back and remove the dummy parameter. Yes, you'll get to have another round of fixing every compilation failure. But each one's trivial, just remove the extra 0 parameter, and this approach guaranteed a proper update to every existing usage of the original constructor.

CodePudding user response:

One approach is to wrap the parameters in your own structure and pass that. This forces subclass construction to use that signature.

It also allows more flexibility if for whatever reason you ever want to add additional stuff to the constructor without going and modifying everything. This technique is used in some APIs to avoid breaking function signatures with minor changes.

I've shown this inline for simplicity, but you could of course hide the implementation if you want.

class MyApplication : public QApplication
{
public:
    struct Args final
    {
        Args(int& argc, char** argv) : argc(argc) , argv(argv) {}
        int& argc;
        char** argv;
    };

    MyApplication(const Args& args)
        : QApplication(args.argc, args.argv)
    {
    }
};

int main(int argc, char** argv)
{
    MyApplication myapp({argc, argv});

    // ...
}

CodePudding user response:

You could pass a pointer to argc like this:

MyApplication(int *argc, char **argv): QApplication(*argc, argv)

That way you force the 'pass by reference' semantic explicitely. Of course you will still need to change all the derived classes, but you will get compilation errors, if you don't. A derived class constructor like

OtherApplication(int argc, char **argv): MyApplication(argc, argv)

will fail to compile and even forces someone who later creates a new derivated class to think about the problem.

  •  Tags:  
  • c qt
  • Related