无法通过C ++中的隐式转换找到运算符

时间:2009-02-19 22:53:16

标签: c++ type-conversion operator-keyword implicit-conversion

当编写一个类作为堆分配对象的包装器时,我遇到了隐式类型转换的问题,可以简化为这个简单的例子。

在下面的代码中,包装器类管理堆分配的对象,并隐式转换为对该对象的引用。这允许包装器对象作为参数传递给函数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";
}

5 个答案:

答案 0 :(得分:2)

它失败了,因为您正在尝试解析不存在的wrapper<T>类的运算符。如果你希望它在没有演员表的情况下工作,你可以将这样的东西放在一起:

template<typename X> wrapper<T> &operator <<(X &param) 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)

经过一些测试,一个更简单的例子确定了问题的根源。编译器无法从隐式转换Tf2(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引用。因此,您的转换运算符不匹配。

正如评论中所述:这是无关紧要的。

标准中有关应用转化的各种限制...当应该应用最多一个时,可能需要隐式转换(您的运算符和转换为基类型)。