我无法理解为什么一个模板实例化在我的代码中有效,而另一个却不能。
我正在使用我创建的这个类模板:
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;
};
这个代码可以工作
Allocated<int> u = 7;
bool k1 = u.get() == u.get();
bool k2 = u == u; // this works fine and calls `operator T&`
虽然这不是
Allocated<std::string> u = "test";
bool k1 = u.get() == u.get();
bool k2 = u == u; // error here
问题1:为什么int调用
operator T&
而不是std::string?
问题2:如何修复任意类型的问题?我不想在
operator==
中定义 Allocated
,它应该适用于其他运算符,例如 Allocated<int>.operator>(Allocated<int>)
。
此代码的问题在于它依赖于
operator ==
为隐式类型转换提供上下文。它适用于 int
,因为有一个内置的 bool operator ==(int, int)
候选者。当编译器检查这个候选函数时,它知道参数的类型,并且能够通过调用 Allocated::operator int const &
来执行隐式类型转换。但是它不适用于 string
,因为 string
的对应运算符实际上是一个模板(因为 std::string
是 std::basic_string
的别名),因此当编译器检查此候选者时,它不知道参数类型,需要推断它们。
以下简化示例说明了差异:
template <typename T>
struct Allocated
{
operator T const & () const;
};
struct NotTemplate{};
bool operator ==(NotTemplate const &, NotTemplate const &);
Allocated<NotTemplate> not_template{};
bool not_template_cmp{not_template == not_template}; // ok
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 matching...
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