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>)例如。
此代码的问题在于它依赖于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不为空)。