1

我正在尝试通过使用 Boost 基本用法在线教程( http://www.boost.org/doc/libs/1_34_0/doc/html/variant/tutorial.html)来学习如何使用 Boost::variant 。为了掌握它,我尝试从教程(下)中获取一些代码......

#include "boost/variant.hpp"
#include <iostream>
#include <complex>

void times_two(boost::variant<int, std::string, std::complex<double> > & v) {
    if (int* pi = boost::get<int>(&v))
        *pi *= 2;
    else if (std::string* pstr = boost::get<std::string>(&v))
        *pstr += *pstr;
    //No check for complex - will silently return when variant is complex (BAD).
}

int main() {
    boost::variant<int, std::string, std::complex<double> > v;
    v = "hello";
    std::string& str = boost::get<std::string>(v);
    str += " world! ";
//the std::string contained by v now is equal to "hello world! ". Again, we can demonstrate this by streaming v to standard output:
    std::cout << v << std::endl;
    times_two(v);
    std::cout << v << std::endl;
    std::complex<double> a(5.0, 6.0);
    v = a;
    times_two(v);
    return 0;
}

^ 它编译良好并返回“hello world!hello world!hello world!” 正如预期的那样,在返回之前采用复杂类型。

然后我尝试修改它...

但是,只要我将自己的结构“structy”添加到变体示例程序中,就像这样:

#include "boost/variant.hpp"
#include <iostream>
#include <complex>

struct structy {
    int a;
};

void times_two(
        boost::variant<int, std::string, std::complex<double>, structy> & v) {
    if (int* pi = boost::get<int>(&v))
        *pi *= 2;
    else if (std::string* pstr = boost::get<std::string>(&v))
        *pstr += *pstr;
    //No check for complex or structy - should silently returns.
}

int main() {

    boost::variant<int, std::string, std::complex<double>, structy> v;
    v = "hello";
    std::string& str = boost::get<std::string>(v);
    str += " world! ";
//As desired, the std::string contained by v now is equal to "hello world! ". Again, we can demonstrate this by streaming v to standard output:
    std::cout << v << std::endl;
    times_two(v);
    std::cout << v << std::endl;
    std::complex<double> a(5.0, 6.0);
    v = a;
    times_two(v);
    return 0;
}

使用 g++4.7 编译时收到大量错误消息。我不明白它在说什么,但我将其包括在内以供参考。

为什么我不能让它与我定义的数据类型一起工作?请注意,当我尝试将 boost::static_visitor 与我自己的用户定义类一起使用时,我也会收到同样的巨大错误消息。

大错误信息如下:

johnmichaelreed@Ubuntu1204LTS:~/Downloads/boost_1_54_0$ g++ ~/temp.cpp -o temp 
In file included from /usr/local/include/boost/variant/variant.hpp:2416:0,
             from /usr/local/include/boost/variant.hpp:17,
             from /home/johnmichaelreed/temp.cpp:1:
/usr/local/include/boost/variant/detail/variant_io.hpp: In member function ‘void boost::detail::variant::printer<OStream>::operator()(const T&) const [with T = structy, OStream = std::basic_ostream<char>]’:
/usr/local/include/boost/variant/variant.hpp:1017:32:   instantiated from ‘boost::detail::variant::invoke_visitor<Visitor>::result_type boost::detail::variant::invoke_visitor<Visitor>::internal_visit(T&, int) [with T = const structy, Visitor = boost::detail::variant::printer<std::basic_ostream<char> >, boost::detail::variant::invoke_visitor<Visitor>::result_type = void]’
/usr/local/include/boost/variant/detail/visitation_impl.hpp:130:9:   instantiated from ‘typename Visitor::result_type boost::detail::variant::visitation_impl_invoke_impl(int, Visitor&, VoidPtrCV, T*, mpl_::true_) [with Visitor = boost::detail::variant::invoke_visitor<boost::detail::variant::printer<std::basic_ostream<char> > >, VoidPtrCV = const void*, T = structy, typename Visitor::result_type = void, mpl_::true_ = mpl_::bool_<true>]’
/usr/local/include/boost/variant/detail/visitation_impl.hpp:173:9:   instantiated from ‘typename Visitor::result_type boost::detail::variant::visitation_impl_invoke(int, Visitor&, VoidPtrCV, T*, NoBackupFlag, int) [with Visitor = boost::detail::variant::invoke_visitor<boost::detail::variant::printer<std::basic_ostream<char> > >, VoidPtrCV = const void*, T = structy, NoBackupFlag = boost::variant<int, std::basic_string<char>, std::complex<double>, structy>::has_fallback_type_, typename Visitor::result_type = void]’
/usr/local/include/boost/variant/detail/visitation_impl.hpp:260:1:   instantiated from ‘typename Visitor::result_type boost::detail::variant::visitation_impl(int, int, Visitor&, VoidPtrCV, mpl_::false_, NoBackupFlag, Which*, step0*) [with Which = mpl_::int_<0>, step0 = boost::detail::variant::visitation_impl_step<boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<4l>, int, boost::mpl::l_item<mpl_::long_<3l>, std::basic_string<char>, boost::mpl::l_item<mpl_::long_<2l>, std::complex<double>, boost::mpl::l_item<mpl_::long_<1l>, structy, boost::mpl::l_end> > > > >, boost::mpl::l_iter<boost::mpl::l_end> >, Visitor = boost::detail::variant::invoke_visitor<boost::detail::variant::printer<std::basic_ostream<char> > >, VoidPtrCV = const void*, NoBackupFlag = boost::variant<int, std::basic_string<char>, std::complex<double>, structy>::has_fallback_type_, typename Visitor::result_type = void, mpl_::false_ = mpl_::bool_<false>]’
/usr/local/include/boost/variant/variant.hpp:2326:13:   instantiated from ‘static typename Visitor::result_type boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::internal_apply_visitor_impl(int, int, Visitor&, VoidPtrCV) [with Visitor = boost::detail::variant::invoke_visitor<boost::detail::variant::printer<std::basic_ostream<char> > >, VoidPtrCV = const void*, T0_ = int, T1 = std::basic_string<char>, T2 = std::complex<double>, T3 = structy, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_, typename Visitor::result_type = void]’
/usr/local/include/boost/variant/variant.hpp:2348:13:   instantiated from ‘typename Visitor::result_type boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::internal_apply_visitor(Visitor&) const [with Visitor = boost::detail::variant::invoke_visitor<boost::detail::variant::printer<std::basic_ostream<char> > >, T0_ = int, T1 = std::basic_string<char>, T2 = std::complex<double>, T3 = structy, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_, typename Visitor::result_type = void]’
/usr/local/include/boost/variant/variant.hpp:2370:52:   instantiated from ‘typename Visitor::result_type boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::apply_visitor(Visitor&) const [with Visitor = boost::detail::variant::printer<std::basic_ostream<char> >, T0_ = int, T1 = std::basic_string<char>, T2 = std::complex<double>, T3 = structy, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_, typename Visitor::result_type = void]’
/usr/local/include/boost/variant/detail/variant_io.hpp:88:5:   instantiated from ‘std::basic_ostream<E, T>& boost::operator<<(std::basic_ostream<E, T>&, const boost::variant<U0, U1, U2, U3, U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16, U17, U18, U19>&) [with E = char, T = std::char_traits<char>, U0 = int, U1 = std::basic_string<char>, U2 = std::complex<double>, U3 = structy, U4 = boost::detail::variant::void_, U5 = boost::detail::variant::void_, U6 = boost::detail::variant::void_, U7 = boost::detail::variant::void_, U8 = boost::detail::variant::void_, U9 = boost::detail::variant::void_, U10 = boost::detail::variant::void_, U11 = boost::detail::variant::void_, U12 = boost::detail::variant::void_, U13 = boost::detail::variant::void_, U14 = boost::detail::variant::void_, U15 = boost::detail::variant::void_, U16 = boost::detail::variant::void_, U17 = boost::detail::variant::void_, U18 = boost::detail::variant::void_, U19 = boost::detail::variant::void_]’
/home/johnmichaelreed/temp.cpp:25:16:   instantiated from here
/usr/local/include/boost/variant/detail/variant_io.hpp:64:9: error: no match for ‘operator<<’ in ‘((const boost::detail::variant::printer<std::basic_ostream<char> >*)this)->boost::detail::variant::printer<std::basic_ostream<char> >::out_ << operand’
/usr/local/include/boost/variant/detail/variant_io.hpp:64:9: note: candidates are:
/usr/include/c++/4.6/ostream:110:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ostream_type& (*)(std::basic_ostream<_CharT, _Traits>::__ostream_type&)) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.6/ostream:110:7: note:   no known conversion for argument 1 from ‘const structy’ to ‘std::basic_ostream<char>::__ostream_type& (*)(std::basic_ostream<char>::__ostream_type&) {aka std::basic_ostream<char>& (*)(std::basic_ostream<char>&)}’
/usr/include/c++/4.6/ostream:119:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ios_type& (*)(std::basic_ostream<_CharT, _Traits>::__ios_type&)) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>, std::basic_ostream<_CharT, _Traits>::__ios_type = std::basic_ios<char>]
/usr/include/c++/4.6/ostream:119:7: note:   no known conversion for argument 1 from ‘const structy’ to ‘std::basic_ostream<char>::__ios_type& (*)(std::basic_ostream<char>::__ios_type&) {aka std::basic_ios<char>& (*)(std::basic_ios<char>&)}’
/usr/include/c++/4.6/ostream:129:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.6/ostream:129:7: note:   no known conversion for argument 1 from ‘const structy’ to ‘std::ios_base& (*)(std::ios_base&)’
/usr/include/c++/4.6/ostream:167:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.6/ostream:167:7: note:   no known conversion for argument 1 from ‘const structy’ to ‘long int’
/usr/include/c++/4.6/ostream:171:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.6/ostream:171:7: note:   no known conversion for argument 1 from ‘const structy’ to ‘long unsigned int’
/usr/include/c++/4.6/ostream:175:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.6/ostream:175:7: note:   no known conversion for argument 1 from ‘const structy’ to ‘bool’
/usr/include/c++/4.6/bits/ostream.tcc:93:5: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.6/bits/ostream.tcc:93:5: note:   no known conversion for argument 1 from ‘const structy’ to ‘short int’
/usr/include/c++/4.6/ostream:182:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.6/ostream:182:7: note:   no known conversion for argument 1 from ‘const structy’ to ‘short unsigned int’
/usr/include/c++/4.6/bits/ostream.tcc:107:5: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.6/bits/ostream.tcc:107:5: note:   no known conversion for argument 1 from ‘const structy’ to ‘int’
/usr/include/c++/4.6/ostream:193:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.6/ostream:193:7: note:   no known conversion for argument 1 from ‘const structy’ to ‘unsigned int’
/usr/include/c++/4.6/ostream:202:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.6/ostream:202:7: note:   no known conversion for argument 1 from ‘const structy’ to ‘long long int’
/usr/include/c++/4.6/ostream:206:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.6/ostream:206:7: note:   no known conversion for argument 1 from ‘const structy’ to ‘long long unsigned int’
/usr/include/c++/4.6/ostream:211:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.6/ostream:211:7: note:   no known conversion for argument 1 from ‘const structy’ to ‘double’
/usr/include/c++/4.6/ostream:215:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.6/ostream:215:7: note:   no known conversion for argument 1 from ‘const structy’ to ‘float’
/usr/include/c++/4.6/ostream:223:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.6/ostream:223:7: note:   no known conversion for argument 1 from ‘const structy’ to ‘long double’
/usr/include/c++/4.6/ostream:227:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.6/ostream:227:7: note:   no known conversion for argument 1 from ‘const structy’ to ‘const void*’
/usr/include/c++/4.6/bits/ostream.tcc:121:5: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__streambuf_type*) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__streambuf_type = std::basic_streambuf<char>]
/usr/include/c++/4.6/bits/ostream.tcc:121:5: note:   no known conversion for argument 1 from ‘const structy’ to ‘std::basic_ostream<char>::__streambuf_type* {aka std::basic_streambuf<char>*}’
/usr/local/include/boost/blank.hpp:93:46: note: template<class E, class T> std::basic_ostream<_CharT, _Traits>& boost::operator<<(std::basic_ostream<_CharT, _Traits>&, const boost::blank&)
/usr/local/include/boost/variant/detail/variant_io.hpp:79:46: note: template<class E, class T, class U0, class U1, class U2, class U3, class U4, class U5, class U6, class U7, class U8, class U9, class U10, class U11, class U12, class U13, class U14, class U15, class U16, class U17, class U18, class U19> std::basic_ostream<E, T>& boost::operator<<(std::basic_ostream<E, T>&, const boost::variant<U0, U1, U2, U3, U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16, U17, U18, U19>&)
/usr/include/c++/4.6/complex:521:5: note: template<class _Tp, class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::complex<_Tp>&)
/usr/include/c++/4.6/ostream:528:5: note: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const unsigned char*)
/usr/include/c++/4.6/ostream:523:5: note: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const signed char*)
/usr/include/c++/4.6/ostream:510:5: note: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const char*)
/usr/include/c++/4.6/bits/ostream.tcc:323:5: note: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const char*)
/usr/include/c++/4.6/ostream:493:5: note: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const _CharT*)
/usr/include/c++/4.6/ostream:473:5: note: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, unsigned char)
/usr/include/c++/4.6/ostream:468:5: note: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, signed char)
/usr/include/c++/4.6/ostream:462:5: note: template<class _Traits> std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, char)
/usr/include/c++/4.6/ostream:456:5: note: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, char)
/usr/include/c++/4.6/ostream:451:5: note: template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, _CharT)
/usr/include/c++/4.6/bits/basic_string.h:2693:5: note: template<class _CharT, class _Traits, class _Alloc> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&)
johnmichaelreed@Ubuntu1204LTS:~/Downloads/boost_1_54_0$ 

这个错误是什么意思?为什么我的修改会破坏代码?

4

1 回答 1

2

@chris 的猜测是正确的,这是因为缺少运算符 <<。

这些错误是 Boost.Variant 的“设计”,它们可以防止你忘记做一些你必须做的事情来定义正确的variant.

实际上,当您使用boost::variant<T1,T2,T3> v某个函数或运算符时,您希望您将对变量 v 的类型为 T1 的情况进行一些处理,并对变量 v 的类型为 T2 的情况进行一些其他处理,甚至对以下情况进行一些处理v 实际上是 T3 类型。

当您进一步阅读 Variant 教程时,您会发现该函数的推荐实现times_two是通过变体访问者进行的。与您的(初始)实现不同,如果程序员忘记为某些类型 T1、T2、T3 实现访问函数(又名 operator()),后者也会发出错误。

现在,对于标准 C++ 功能(如operator <<(variant<...>,ostream&). 由于您struct structy不允许运算符 <<,因此编译器会发出错误。

不幸的是,错误有点神秘。错误通常是由 operator<< 引起的,因为 C++ 有很多重载,编译器会尝试并提及所有重载。

于 2013-11-03T06:17:22.500 回答