"Ambigous"等效转换 - 我可以让编译器只选择任何一个吗?

"Ambigous" equivalent conversions - can I make the compiler just choose any?

本文关键字:选择 任何一 编译器 Ambigous 转换 我可以      更新时间:2023-10-16

我有一个模拟指针行为的类模板,当强制转换为任何指针类型时,将指针返回到给定的存储内存位置。

它具有转换为多种类型(intptr_t、模拟的本机指针等)的运算符,就像指针的正常情况一样,它返回在这种情况下真实指针将返回的值。

MockPointer<int> TestIntPointer;
MockPointer<int> TestIntPointer2;
int* a = nullptr;
ASSERT_TRUE(TestIntPointer == a);
ASSERT_TRUE(TestIntPointer == TestIntPointer2);

没有bool operator==(MockPointer<T> rhs)我在第二个断言时收到错误:

Multiple markers at this line
- operator==(int*, int*) <built-in>
- candidates are:
- in expansion of macro 'ASSERT_TRUE'
- operator==(intptr_t {aka long int}, intptr_t {aka long int}) <built-in>
- operator==(intptr_t {aka long int}, int) <built-in>
- operator==(int, intptr_t {aka long int}) <built-in>
- operator==(int, int) <built-in>
 ambiguous overload for 'operator==' (operand types are '{anonymous}::MockPointer<int> and '{anonymous}::MockPointer<int>)

使用运算符时,第一个断言失败:

- in expansion of macro 'ASSERT_TRUE'
- ambiguous overload for 'operator==' (operand types are '{anonymous}::MockPointer<int>' and 'int*')
- candidates are:
- operator==(int*, int*) <built-in>

我知道有很多方法可以转换变量并进行比较!为了进行比较,它们的工作方式都相同!我可以以某种方式强制编译器选择第一个可用的转换并使用它,而不是抱怨它无法决定是否应该在茶中加入糖和牛奶,或者更确切地说是牛奶和糖?

编辑:完整代码(运算符==行接近文件的2/3,有些被注释掉了):

    #pragma once
    #include <stdint.h>     //zapewnia stdint_t, specjalny int do przechowywania wskaźników.
    #include "api/utils/tinyutils.h"
    #include "api/standard_exceptions.h"
    namespace Api {
    /**
     * ShmPointer
     * Klasa zachowująca się jak zwykły wskaźnik ale działająca dla w pamięci współdzielonej.
     *
     * Sposób użycia:
     * Każda instancja (wariant) pamięci współdzielonej tworzona jest bądź pobierana przez ShmProvider
     * W szczególności określona instancja to
     *
     *      ShmProvider<typ_shm, klucz_shm> MyShmProvider;
     *
     * Dla niej generujemy template pointerów do wszystkiego, co można w tejże pamięci znaleźć:
     *
     *      template <class T>using MyShmPointer = ShmPointer<T,MyShmProvider>;
     *
     *      Potem już tylko:
     *      MyShmPointer<Grupa> gr = &(MyShmProvider::Base->Grupy[5]);  //cast zwykłego wskaźnika na ShmPointer
     *
     *      MyShmProvider::Base->AktywnaGrupa = gr;     //przypisanie jednego ShmPointer do drugiego, leżącego w SHM
     *
     *      // w zupełnie innym programie
     *      display(MyShmProvider::Base->AktywnaGrupa->kolor);  //odczytanie wartości po wskaźniku
     */
    template<class T, class ShmProvider>
    class ShmPointer
    {
    private:
        int offset = -1;
        bool IsEmpty() const {
            return offset == -1;
        }
        T* MyAddress() {
            if(unlikely(IsEmpty()))
                return nullptr;
            return (T*)((char*)ShmProvider::Base + offset);
        }
        T* Add(int count) {
            return reinterpret_cast<T*>((char*)MyAddress() + count*sizeof(T));
        }
    public:
        ShmPointer() = default;
        //Konstruktor na podstawie wskaźnika.
        ShmPointer(T* shmaddr) : offset((char*)shmaddr - (char*)ShmProvider::Base) {
        }
        // Operatory rzutowania
        //Cast na typ "wskaźnik do T"
        operator T*() {
            return MyAddress();
        }
        //Cast na typ boolean
        operator bool() {
            return !IsEmpty();
        }
        //rzutowanie na int
        operator intptr_t() {
            return (intptr_t) MyAddress();
        }
        // Standardowe operatory (znaczki)
        //Dereferencja na pole
        T* operator->()
        {
            if(IsEmpty()) throw( NullPointerDereferenceException(LOCATION) );
            return MyAddress();
        }
        //Dereferncja wprost
        T& operator*()
        {
            if(IsEmpty()) throw( NullPointerDereferenceException(LOCATION) );
            return *(MyAddress());
        }
        //Przypisanie
        T* operator=(T* shmaddr)
        {
            if(shmaddr==nullptr)
            {
                offset=-1;
                return nullptr;
            }
            offset = (char*)shmaddr - (char*)ShmProvider::Base;
            return MyAddress();
        }
        //Dereferencja nawiasami
        T& operator[](int ndx)
        {
            if(IsEmpty()) throw(NullPointerDereferenceException(LOCATION));
            return (T&) *(Add(ndx));
        }
        T* operator+(int ndx)
        {
            if(IsEmpty())
                return nullptr;
            return Add(ndx);
        }
        T* operator-(int arg)
        {
            if(IsEmpty())
                return nullptr;
            return Add(-arg);
        }
        intptr_t operator-(T* arg)
        {
            if(MyAddress() == nullptr){ return 0; }
            return (intptr_t)((char*)MyAddress() - (char*)arg);
        }
        bool operator!()
        {
            return offset == -1;
        }
        bool operator==(const Api::ShmPointer<T, ShmProvider>& rhs) const {
            return offset == rhs.offset;
        }
        bool operator==(const std::nullptr_t rhs) const {
            return IsEmpty();
        }
    /*
        bool operator==(const T* rhs) const {
            return (MyAddress() == rhs);
        }
    */
        /*
        bool operator!=(const ShmPointer<T, ShmProvider>& rhs) const {
            return !(*this == rhs);
        }
    */
        bool operator!=(const std::nullptr_t rhs) const {
            return !(*this == rhs);
        }
    /*
        bool operator!=(const T* rhs) const {
            return !(MyAddress() == rhs);
        }
    */
        T* operator++()
        {
            if(IsEmpty())
                return nullptr;
            offset += sizeof(T);
            return MyAddress();
        }
        T* operator++(int)
        {
            if(IsEmpty())
                return nullptr;
            T* dummy = MyAddress();
            offset += sizeof(T);
            return dummy;
        }
        T* operator--()
        {
            if(IsEmpty()) return nullptr;
            offset -= sizeof(T);
            return MyAddress();
        }
        T* operator--(int)
        {
            if(IsEmpty()) return nullptr;
            T* dummy = MyAddress();
            offset -= sizeof(T);
            return dummy;
        }
    };
    }

这是由于大量的转换运算符和通过构造函数的隐式转换。您应该能够通过以下方式避免歧义

  1. 提供完美匹配的比较运算符

    bool operator==(const MockPointer<T>& rhs);

  2. 使构造函数显式T*

    explicit MockPointer(T*);

我在 http://coliru.stacked-crooked.com/a/73300327b4fcfac8 上做了一个你可以玩的活例子;尝试从构造函数中删除explicit关键字,它重现了你在问题和评论中描述的问题。允许编译器为隐式转换留出太多的自由度通常会导致歧义,因为编译器有太多方法来实现函数调用。

删除一个或多个隐式转换也可能获得一些结果。