当编写一个类作为堆分配对象的包装器时,我遇到了隐式类型转换的问题,可以简化为这个简单的例子。
在下面的代码中,包装器类管理堆分配的对象,并隐式转换为对该对象的引用。这允许包装器对象作为参数传递给函数write(...),因为发生了隐式转换。
但是,在尝试解析对运算符&lt;&lt;(...)的调用时,编译器失败,除非进行显式强制转换(使用MSVC8.0,Intel 9.1和gcc 4.2.1编译器进行检查)。< / p>
那么,(1)为什么隐式转换在这种情况下会失败? (2)它可能与参数依赖查找有关吗? (3)有没有什么可以在没有明确演员的情况下完成这项工作?
#include <fstream>
template <typename T>
class wrapper
{
T* t;
public:
explicit wrapper(T * const p) : t(p) { }
~wrapper() { delete t; }
operator T & () const { return *t; }
};
void write(std::ostream& os)
{
os << "(1) Hello, world!\n";
}
int main()
{
wrapper<std::ostream> file(new std::ofstream("test.txt"));
write(file);
static_cast<std::ostream&>( file ) << "(2) Hello, world!\n";
// file << "(3) This line doesn't compile!\n";
}
答案 0 :(得分:2)
它失败了,因为您正在尝试解析不存在的wrapper<T>
类的运算符。如果你希望它在没有演员表的情况下工作,你可以将这样的东西放在一起:
template<typename X> wrapper<T> &operator <<(X ¶m) const {
return t << param;
}
不幸的是我不知道在编译时解决返回类型的方法。幸运的是,在大多数情况下,它与对象的类型相同,包括ostream
的情况。
编辑:根据dash-tom-bang的建议修改代码。将退货类型更改为wrapper<T> &
。
答案 1 :(得分:1)
编译器没有足够的上下文来确定operator&
将进行有效转换。所以,是的,我认为这与依赖于参数的查找有关:编译器正在寻找可以接受非operator<<
const
作为其第一个参数的wrapper<std::ostream>
。
答案 2 :(得分:1)
我认为问题与维护一些编译时限制有关。在您的示例中,编译器首先必须找到 all 可能的运算符&lt;&lt;。然后,对于它们中的每一个,如果您的对象可以(直接或间接)自动转换为每个运算符&lt;&lt;&lt;能够接受。
这个测试可能非常复杂,我认为这仅限于提供合理的编译时间。
答案 3 :(得分:1)
经过一些测试,一个更简单的例子确定了问题的根源。编译器无法从隐式转换T
到f2(const bar<T>&)
推导出wrapper<bar<int> >
中的模板参数bar<int>&
。
template <typename T>
class wrapper
{
T* t;
public:
explicit wrapper(T * const p) : t(p) { }
~wrapper() { delete t; }
operator T & () const { return *t; }
};
class foo { };
template <typename T> class bar { };
void f1(const foo& s) { }
template <typename T> void f2(const bar<T>& s) { }
void f3(const bar<int>& s) { }
int main()
{
wrapper<foo> s1(new foo());
f1(s1);
wrapper<bar<int> > s2(new bar<int>());
//f2(s2); // FAILS
f2<int>(s2); // OK
f3(s2);
}
在原始示例中,std::ostream
实际上是模板化类typedef
的{{1}},调用模板化函数std::basic_ostream<..>
时也适用相同的情况。
答案 4 :(得分:0)
检查插入操作符的签名...我认为它们采用非const ostream引用?
使用C ++ 03标准确认,char *输出运算符的签名是:
template<class charT, class traits>
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
确实采用非const引用。因此,您的转换运算符不匹配。
正如评论中所述:这是无关紧要的。
标准中有关应用转化的各种限制...当应该应用最多一个时,可能需要隐式转换(您的运算符和转换为基类型)。