【问题标题】:Boost.Test output_test_stream fails with templated output operatorBoost.Test output_test_stream 因模板化输出运算符而失败
【发布时间】:2011-03-12 06:04:06
【问题描述】:

我有一堂课:

class foo {
private:
    std::string data;
public:
    foo &append(const char* str, size_t n) { data.append(str,n); }

    // for debug output
    template <typename T>
    friend T& operator<< (T &out, foo const &f);

    // some other stuff
};

template <typename T>
T& operator<< (T &out, foo const &f) {
    return out << f.data;
}

我希望它适用于任何提供 &lt;&lt; 运算符的类。

这适用于std::cout,如下所示:

std::cout << fooObject;

但以下失败:

BOOST_AUTO_TEST_CASE( foo_append_and_output_operator )
{
    // fooObject is accessable here
    const char* str = "hello";
    fooObject.append(str, strlen(str));

    output_test_stream output;
    output << fooObject;

    BOOST_CHECK( output.is_equal(str) );
}

g++ 告诉我:

In function ‘T& operator<<(T&, const foo&) 
    [with T = boost::test_tools::output_test_stream]’:
error: invalid initialization of reference of type
    ‘boost::test_tools::output_test_stream&’ from expression of type
    ‘std::basic_ostream<char, std::char_traits<char> >’

发生了什么事?

我在 Ubuntu 8.04 上使用 Boost 1.34.1

【问题讨论】:

  • BOOST_AUTO_TEST_CASE 代码中的“foo”是什么——类名还是变量名?
  • @jon hanson:错字,看我的编辑。现在应该清楚了。
  • 那绝对是正确的代码吗?上面代码中任何地方都没有出现的ostream是怎么出现在错误中的?

标签: c++ unit-testing templates boost


【解决方案1】:

是错字吗?你写的

foo.append(str, strlen(str));

foo 是类的名称而不是对象。

【讨论】:

    【解决方案2】:

    您可能已经知道了,但是使用 output_test_stream 作为 std::ostream 可以:

    class foo {
        // [...]
        friend
        std::ostream& operator<< ( std::ostream &os, const foo &f );
    };
    
    std::ostream& operator<< ( std::ostream &os, const foo &f ) {
        return os << f.data;
    }
    

    【讨论】:

    • 很好,但是当operator&lt;&lt; 被模板化时为什么它不起作用?
    • 好吧,不幸的是,看起来output &lt;&lt; fooObject 返回了一个std::ostream。因此,无法实例化模板函数。我认为 Space_C0wb0y 已经付出了一些努力来研究细节。对于您的问题,我提出的代码应该是解决方案。
    • 谢谢,虽然这可以解决我的问题,但不能回答我的问题。
    【解决方案3】:

    所以我想我有一个解释,但还没有解决方案。 output_test_stream 通过继承 wrap_stringstream 来实现其流功能。这个的插入操作符是一个免费的函数模板,看起来像这样:

    template <typename CharT, typename T>
    inline basic_wrap_stringstream<CharT>&
    operator<<( basic_wrap_stringstream<CharT>& targ, T const& t )
    {
        targ.stream() << t;
        return targ;
    }
    
    // ... further down in the same header
    
    typedef basic_wrap_stringstream<char>       wrap_stringstream;
    

    您的运算符以output_test_stream 作为流类型调用,这使其成为返回类型。然后您的运算符调用上述运算符,并仅传播返回值。然而,上述运算符的返回值是运算符返回类型的超类。当编译器尝试创建您想要返回的引用时,它会阻塞,因为它无法从对超类的引用初始化对子类的引用,即使两者都引用同一个对象。这有意义吗?

    【讨论】:

    • 是的,有点意思...我现在正在查看 Boost 头文件,以尝试更好地理解它。
    • 你知道这在新版本的 Boost 中是否仍然是一个问题吗?
    • 你只需要比较标题wrap_stringstream.hpp。您可以将上面链接中的版本号更改为最新版本,我认为是 1.43.0。
    猜你喜欢
    • 2015-12-26
    • 2021-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-29
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多