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

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

我有一个模拟指针行为的 class 模板,return在转换为任何指针类型时将指针指向给定的存储内存位置。

它具有转换为多种类型的运算符(intptr_t,它正在模拟的本机指针等),对于指针来说是正常的,并且它 return 的值是一个真正的指针 return 那样的话。

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>

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

编辑:完整代码(Operator== 行接近文件的 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 关键字,这会重现您在问题和评论中描述的问题。允许编译器对隐式转换有太多自由度通常会导致歧义,因为编译器只是有太多方法来进行函数调用。

您还可以从删除一个或多个隐式转换中获得一些结果。