Aufruf bestimmter Überladung erzwingen



  • Hallo Forum,

    bei der Verwendung einer OpenCV-Klasse habe ich Probleme, den Aufruf eines bestimmten Konstruktors zu erzwingen.
    Es geht um die Klasse Mat_, die einfach eine templated Matrix-Klasse darstellt und einen Konstruktor hat, mit dem man die Matrix-Elemente direkt initialisieren kann.
    Hier ein Auszug aus der Klasse:

    template<typename _Tp> 
    class Mat_ : public Mat
    {
    public:
        //! constructor that sets each matrix element to specified value
        Mat_(int _rows, int _cols, const _Tp& value);
        //! constructs n-dim matrix on top of user-allocated data. steps are in bytes(!!!), regardless of the type
        Mat_(int _ndims, const int* _sizes, _Tp* _data, const size_t* _steps=0);
    }
    

    Ich würde nun gerne den ersten der beiden oben aufgeführten Konstruktoren nutzen, um meine Matrix folgendermaßen zu initialisieren:

    cv::Mat_<MyClass*> data(42, 42, nullptr);
    

    Dieser Aufruf ist mehrdeutig, weil er für beide Konstruktoren funktioniert. Habe ich aufruferseitig irgendeine Chance Eindeutigkeit herzustellen?



  • Sorry, Fehler im Originalpost. Der zweite Konstruktor sieht folgendermaßen aus:

    //! constructs a matrix on top of user-allocated data. step is in bytes(!!!), regardless of the type
        Mat_(int _rows, int _cols, _Tp* _data, size_t _step=AUTO_STEP);
    


  • nullptr und const _Tp& value passt nicht.



  • Warum verwendest du überhaupt Zeiger anstatt direkt die Klasse zu benutzen?

    cv::Mat_<MyClass> data(42, 42, MyClass());
    


  • manni66 schrieb:

    nullptr und const _Tp& value passt nicht.

    Ist mir nicht hundertprozentig klar.

    Sollte hier nicht _Tp als MyClass* deduziert werden und somit der Parameter als const MyClass*&. (Kein schönes Konstrukt, aber doch technisch in Ordnung, oder?)

    Und darf dann nicht das Argument des Aufrufs ein nullptr sein?

    Mein Compiler (ich arbeite mit Visual Studio 2017), schlägt das auch als mögliche Überladung vor. (Die absoluten Pfade habe ich aus dem Output entfernt und MyClass heißt in Wirklichkeit anders, aber ansonsten ist das die Originalausgabe des Compilers).

    error C2668: 'cv::Mat_<MyClass*>::Mat_': ambiguous call to overloaded function
    1>opencv2/core/core.hpp(2783): note: could be 'cv::Mat_<MyClass*>::Mat_(const cv::Mat_<MyClass*> &,const cv::Range &,const cv::Range &)'
    1>opencv2/core/core.hpp(2781): note: or       'cv::Mat_<MyClass*>::Mat_(int,const int *,_Tp *,const size_t *)'
    1>        with
    1>        [
    1>            _Tp=MyClass*
    1>        ]
    1>opencv2/core/core.hpp(2779): note: or       'cv::Mat_<MyClass*>::Mat_(int,int,_Tp *,::size_t)'
    1>        with
    1>        [
    1>            _Tp=MyClass*
    1>        ]
    1>opencv2/core/core.hpp(2773): note: or       'cv::Mat_<MyClass*>::Mat_(int,const int *,const _Tp &)'
    1>        with
    1>        [
    1>            _Tp=MyClass*
    1>        ]
    1>opencv2/core/core.hpp(2765): note: or       'cv::Mat_<MyClass*>::Mat_(int,int,const _Tp &)'
    1>        with
    1>        [
    1>            _Tp=MyClass*
    1>        ]
    1>note: while trying to match the argument list '(int, int, nullptr)'
    


  • Th69 schrieb:

    Warum verwendest du überhaupt Zeiger anstatt direkt die Klasse zu benutzen?

    Ich arbeite leider nicht an meinem eigenen Code und das ist in diesem Fall tatsächlich eine berechtigte Frage, aber auch dafür ließen sich doch Gründe finden.

    Nehmen wir an "MyClass" wäre eine Klasse aus einer Bibliothek auf die ich keinen Zugriff habe. Wenn ich jetzt für Instanzen von "MyClass" eine Art Default oder ungültigen Zustand speichern wollte und ein mit dem Default-Konstruktor erzeugtes Objekt aber einen gültigen Zustand darstellt. Dann wäre die Verwendung von MyClass-Pointer und nullptr als ungültiger Zustand zumindest eine Möglichkeit.

    Ist aber jetzt ein wenig off-topic. Mir ging es vor allem darum, zu erfahren, ob man hier irgendwelche Möglichkeiten hat, den Aufruf eines bestimmten Konstruktors zu erzwingen. Ich werde mir mit ziemlicher Sicherheit komplett anders behelfen, aber die Frage interessiert mich trotzdem ;).



  • Ambiguous Caller schrieb:

    Sollte hier nicht _Tp als MyClass* deduziert werden und somit der Parameter als const MyClass*&. (Kein schönes Konstrukt, aber doch technisch in Ordnung, oder?)

    Ja

    Ambiguous Caller schrieb:

    Und darf dann nicht das Argument des Aufrufs ein nullptr sein?

    Warum sollte es das dann dürfen?
    Was bedeutet das & an dieser Stelle?



  • Ok, ich ziehe den Einwand zurück.

    somit der Parameter als const MyClass*&

    Nein, dachte ich auch, aber es ist MyClass* const&.



  • Ich hätte jetzt behauptet, die beiden sind synonym. Also quasi

    const (MyClass*)&
    

    entspricht

    (MyClass*) const&
    

    Aber ich habe mit sowas jetzt auch nicht unbedingt täglich zu tun.



  • Ambiguous Caller schrieb:

    Mir ging es vor allem darum, zu erfahren, ob man hier irgendwelche Möglichkeiten hat, den Aufruf eines bestimmten Konstruktors zu erzwingen.

    Du musst genau die passenden Aufrufparameter liefern. Das muss eindeutig sein.

    cv::Mat_<MyClass*> data(42, 42, static_cast<MyClass*>(nullptr));
    

    sollte es tun.



  • Das entspricht aber dem Aufruf des 2. Konstruktors.
    Für den ersten also

    cv::Mat_<MyClass*> data(42, 42, static_cast<const MyClass*&>(nullptr));
    


  • Th69 schrieb:

    Das entspricht aber dem Aufruf des 2. Konstruktors.

    Der erwartet ein MyClass**, sollte also nicht gefunden werden.



  • Ups, stimmt - jetzt bin ich doch mit meinem eigenen Vorschlag durcheinandergekommen.



  • manni66 schrieb:

    Du musst genau die passenden Aufrufparameter liefern. Das muss eindeutig sein.

    C++:
    cv::Mat_<MyClass*> data(42, 42, static_cast<MyClass*>(nullptr));
    

    sollte es tun.

    Ja, das funktioniert und beantwortet meine Frage, danke!

    (Ich bekomme dann leider einen weiteren Compilerfehler für den Zuweisungsoperator von cv::Mat_. Die Möglichkeit in cv::Mat_ mit Pointern als Template-Parameter zu arbeiten ist also offensichtlich nicht wirklich vorgesehen.)