C++ 运算符 == 的隐式转换

Bru*_* CL 4 c++ implicit-conversion

我无法理解为什么一个模板实例化在我的代码中有效,而另一个却不能。

我正在使用我创建的类模板:

template <typename T>
struct Allocated {
public:
    const T& get() const& {
        return *ptr.get();
    }
    T& get() & {
        return *ptr.get();
    }
    T&& get() && {
        return std::move(*ptr.get());
    }

    operator T& () & {
        return *ptr.get();
    }

    operator const T& () const & {
        return *ptr.get();
    }

    operator const T () && {
        return std::move(* ptr.get());
    }

    template <typename U>
    Allocated(const U& u) : ptr(std::make_unique<T>(u)) {}
    template <typename U>
    Allocated(U&& u) : ptr(std::make_unique<T>(std::move(u))) {}
    Allocated()  = delete;
    Allocated(const Allocated& other) : Allocated(other.get()) {};
    Allocated& operator=(const Allocated& other) {
        ptr = std::make_unique<T>(*other.ptr);
    }
    Allocated(Allocated&& other) : Allocated(other.get()) {};
    Allocated& operator=(Allocated&& other) {
        ptr = std::move(other.ptr);
        return *this;
    }
    ~Allocated() = default;
protected:
    std::unique_ptr<T> ptr;
};
Run Code Online (Sandbox Code Playgroud)

这段代码有效

    Allocated<int> u = 7;
    bool k1 = u.get() == u.get();
    bool k2 = u == u; // this works fine and calls `operator T&`
Run Code Online (Sandbox Code Playgroud)

虽然这并不

    Allocated<std::string> u = "test";
    bool k1 = u.get() == u.get();
    bool k2 = u == u; // error here
Run Code Online (Sandbox Code Playgroud)

问题1:为什么operator T&调用int而不是std::string?

问题2:如何针对任何类型修复它?我不想定义operator==in Allocated,它应该适用于其他运算符,Allocated<int>.operator>(Allocated<int>)例如。

use*_*670 6

此代码的问题在于它依赖于operator ==为隐式类型转换提供上下文。它之所以有效,int是因为有一个内置的bool operator ==(int, int)候选者。当编译器检查此候选函数时,它知道参数的类型,并且能够通过调用执行隐式类型转换Allocated::operator int const &。但是它不起作用,string因为对应的运算符 forstring实际上是 a template(因为std::string是 for 的别名std::basic_string template),因此当编译器检查此候选者时,它不知道参数的类型,需要首先推断它们。

以下简化示例说明了差异:

template <typename T>
struct Allocated
{
    operator T const & () const;
};
Run Code Online (Sandbox Code Playgroud)

已知运算符 == 的参数类型为NotTemplate const &,导致隐式转换成功。 在线编译器

struct NotTemplate{};

bool operator ==(NotTemplate const &, NotTemplate const &);

Allocated<NotTemplate> not_template{};
bool not_template_cmp{not_template == not_template}; // ok
Run Code Online (Sandbox Code Playgroud)

的论证类型operator ==是事先未知的,首先Dummy必须从 中推导出来Allocated<Template<void>>,这是不可能的。 在线编译器

template<typename Dummy>
struct Template{};

template<typename Dummy>
bool operator ==(Template<Dummy> const &, Template<Dummy> const &);

Allocated<Template<void>> _template{};
bool _template_cmp{_template == _template}; // error, no match...
Run Code Online (Sandbox Code Playgroud)

operator ==已知附加重载的参数类型为Template<void>,从而导致成功的隐式转换。 在线编译器

template<typename Dummy>
struct Template{};

template<typename Dummy>
bool operator ==(Template<Dummy> const &, Template<Dummy> const &);

bool operator ==(Template<void> const &, Template<void> const &);

Allocated<Template<void>> _template{};
bool _template_cmp{_template == _template}; // ok
Run Code Online (Sandbox Code Playgroud)

处理这个问题的一种方法是为类实现operator ==(或者甚至可能T const &是新的 C++ 标准中的宇宙飞船运算符)重载,包括那些接受参数之一的重载Allocated(顺便说一句,它可能应该检查它ptr不为空)。