1

我已经定义了一个 boost::spirit::qi 规则:

boost::spirit::qi::rule<Iterator, Identifier()> id;

其中标识符定义为:

BOOST_STRONG_TYPEDEF(std::string, Identifier)

但是当我使用

BOOST_SPIRIT_DEBUG_NODE(id);

它无法编译并出现以下错误:

boost_1_51_0/boost/spirit/home/support/attributes.hpp:1203: error: no match for 'operator<<' in 'out << val'

它列出了 ostream 的重载运算符。

知道 BOOST_STRONG_TYPEDEF 为原始类型定义了一个强制转换运算符,编译器不应该在使用时从 Identifier 隐式强制转换为 std::stringoperator<<吗?或者是否存在阻止编译器在尝试匹配另一个运算符(即operator<<)时应用类型的强制转换运算符的限制?

当我定义以下运算符时,它会编译:

inline std::ostream& operator<<(std::ostream& os, const Identifier& id)
{
    return os << static_cast<std::string const&>(id);
}

我正在使用 gcc4.4.2

4

1 回答 1

4

这与 boost、strong_typedef 或精神无关。

It has a lot to do with type deduction for template arguments. In short, when argument types are deduced, implicit conversions never take place [1]

Cf.:

#include <iostream>
#include <string>
#include <boost/strong_typedef.hpp>

BOOST_STRONG_TYPEDEF(double, X)
int main() { std::cout << X(); }

No problem! Replace double by std::string, and it doesn't work anymore. What's different?

The declaration of the streaming operator differs.

Contrast

ostream& ostream::operator<<(double);

To

template<typename _CharT, typename _Traits, typename _Alloc>
   inline basic_ostream<_CharT, _Traits>&
   operator<<(basic_ostream<_CharT, _Traits>&, basic_string<_CharT, _Traits, _Alloc> const&)

The fact that the operator overload is a function template disallows any implicit conversions.


[1] I guess initializer_list may look like a bit of an exception here, what with widening/narrowing that it can do. Different subject, though

于 2013-01-31T23:10:30.337 回答