使用自定义访问者时自定义类型的 Boost 变体失败(源自 boost::static_visitor)
Boost variant with custom type failing when using custom visitor (derived from boost::static_visitor)
我正在试验 boost::variant 并使用标准类型打印,如下所示,有效。
typedef boost::variant<int, std::string> myVariant;
myVariant my;
my = "Hello";
std::cout << my << endl;
但是当我引入自定义类型时
struct MyStructTag
{
uint32_t ver;
double kind;
std::string type;
};
typedef boost::variant<MyStructTag, std::string> myVariant;
它抛出以下错误,但无法完全理解。
main.cpp: In instantiation of ‘std::ostream& test_variant::custom_ostream::operator()(const T&) const [with T = test_variant::MyStructTag; std::ostream = std::basic_ostream<char>]’:
v_1_55_0/boost/variant/variant.hpp:938:32: required from ‘boost::detail::variant::invoke_visitor<Visitor>::result_type boost::detail::variant::invoke_visitor<Visitor>::internal_visit(T&, int) [with T = const test_variant::MyStructTag; Visitor = const test_variant::custom_ostream; boost::detail::variant::invoke_visitor<Visitor>::result_type = std::basic_ostream<char>&]’
v_1_55_0/boost/variant/detail/visitation_impl.hpp:113:9: required 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<const test_variant::custom_ostream>; VoidPtrCV = const void*; T = test_variant::MyStructTag; typename Visitor::result_type = std::basic_ostream<char>&; mpl_::true_ = mpl_::bool_<true>]’
v_1_55_0/boost/variant/detail/visitation_impl.hpp:156:9: required from ‘typename Visitor::result_type boost::detail::variant::visitation_impl_invoke(int, Visitor&, VoidPtrCV, T*, NoBackupFlag, int) [with Visitor = boost::detail::variant::invoke_visitor<const test_variant::custom_ostream>; VoidPtrCV = const void*; T = test_variant::MyStructTag; NoBackupFlag = boost::variant<test_variant::MyStructTag, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::has_fallback_type_; typename Visitor::result_type = std::basic_ostream<char>&]’
v_1_55_0/boost/variant/detail/visitation_impl.hpp:237:5: required 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_<2l>, test_variant::MyStructTag, boost::mpl::l_item<mpl_::long_<1l>, std::basic_string<char>, boost::mpl::l_end> > >, boost::mpl::l_iter<boost::mpl::l_end> >; Visitor = boost::detail::variant::invoke_visitor<const test_variant::custom_ostream>; VoidPtrCV = const void*; NoBackupFlag = boost::variant<test_variant::MyStructTag, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::has_fallback_type_; typename Visitor::result_type = std::basic_ostream<char>&; mpl_::false_ = mpl_::bool_<false>]’
v_1_55_0/boost/variant/variant.hpp:2237:13: required from ‘static typename Visitor::result_type boost::variant<T0, TN>::internal_apply_visitor_impl(int, int, Visitor&, VoidPtrCV) [with Visitor = boost::detail::variant::invoke_visitor<const test_variant::custom_ostream>; VoidPtrCV = const void*; T0_ = test_variant::MyStructTag; TN = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; typename Visitor::result_type = std::basic_ostream<char>&]’
v_1_55_0/boost/variant/variant.hpp:2259:13: required from ‘typename Visitor::result_type boost::variant<T0, TN>::internal_apply_visitor(Visitor&) const [with Visitor = boost::detail::variant::invoke_visitor<const test_variant::custom_ostream>; T0_ = test_variant::MyStructTag; TN = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; typename Visitor::result_type = std::basic_ostream<char>&]’
v_1_55_0/boost/variant/variant.hpp:2281:52: required from ‘typename Visitor::result_type boost::variant<T0, TN>::apply_visitor(Visitor&) const [with Visitor = const test_variant::custom_ostream; T0_ = test_variant::MyStructTag; TN = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; typename Visitor::result_type = std::basic_ostream<char>&]’
v_1_55_0/boost/variant/detail/apply_visitor_unary.hpp:74:43: required from ‘typename Visitor::result_type boost::apply_visitor(const Visitor&, Visitable&) [with Visitor = test_variant::custom_ostream; Visitable = const boost::variant<test_variant::MyStructTag, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >; typename Visitor::result_type = std::basic_ostream<char>&]’
main.cpp:34:59: required from here
main.cpp:23:21: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
return os_ << val;
^
In file included from /usr/include/c++/4.8.2/iostream:39:0,
from main.cpp:1:
/usr/include/c++/4.8.2/ostream:602:5: error: initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = test_variant::MyStructTag]’
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
In file included from v_1_55_0/boost/variant/variant.hpp:2325:0,
from v_1_55_0/boost/variant.hpp:17,
from main.cpp:2:
v_1_55_0/boost/variant/detail/variant_io.hpp: In instantiation of ‘void boost::detail::variant::printer<OStream>::operator()(const T&) const [with T = test_variant::MyStructTag; OStream = std::basic_ostream<char>]’:
v_1_55_0/boost/variant/variant.hpp:938:32: required from ‘boost::detail::variant::invoke_visitor<Visitor>::result_type boost::detail::variant::invoke_visitor<Visitor>::internal_visit(T&, int) [with T = const test_variant::MyStructTag; Visitor = boost::detail::variant::printer<std::basic_ostream<char> >; boost::detail::variant::invoke_visitor<Visitor>::result_type = void]’
v_1_55_0/boost/variant/detail/visitation_impl.hpp:113:9: required 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 = test_variant::MyStructTag; typename Visitor::result_type = void; mpl_::true_ = mpl_::bool_<true>]’
v_1_55_0/boost/variant/detail/visitation_impl.hpp:156:9: required 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 = test_variant::MyStructTag; NoBackupFlag = boost::variant<test_variant::MyStructTag, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::has_fallback_type_; typename Visitor::result_type = void]’
v_1_55_0/boost/variant/detail/visitation_impl.hpp:237:5: required 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_<2l>, test_variant::MyStructTag, boost::mpl::l_item<mpl_::long_<1l>, std::basic_string<char>, 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<test_variant::MyStructTag, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::has_fallback_type_; typename Visitor::result_type = void; mpl_::false_ = mpl_::bool_<false>]’
v_1_55_0/boost/variant/variant.hpp:2237:13: required from ‘static typename Visitor::result_type boost::variant<T0, TN>::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_ = test_variant::MyStructTag; TN = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; typename Visitor::result_type = void]’
v_1_55_0/boost/variant/variant.hpp:2259:13: required from ‘typename Visitor::result_type boost::variant<T0, TN>::internal_apply_visitor(Visitor&) const [with Visitor = boost::detail::variant::invoke_visitor<boost::detail::variant::printer<std::basic_ostream<char> > >; T0_ = test_variant::MyStructTag; TN = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; typename Visitor::result_type = void]’
v_1_55_0/boost/variant/variant.hpp:2281:52: required from ‘typename Visitor::result_type boost::variant<T0, TN>::apply_visitor(Visitor&) const [with Visitor = boost::detail::variant::printer<std::basic_ostream<char> >; T0_ = test_variant::MyStructTag; TN = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; typename Visitor::result_type = void]’
v_1_55_0/boost/variant/detail/variant_io.hpp:88:5: required from ‘std::basic_ostream<_CharT, _Traits>& boost::operator<<(std::basic_ostream<_CharT, _Traits>&, const boost::variant<U0, UN ...>&) [with E = char; T = std::char_traits<char>; U0 = test_variant::MyStructTag; UN = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}]’
main.cpp:47:17: required from here
v_1_55_0/boost/variant/detail/variant_io.hpp:64:14: error: cannot bind ‘std::basic_ostream<char>’ lvalue to ‘std::basic_ostream<char>&&’
out_ << operand;
完整代码
#include <iostream>
#include <boost/variant.hpp>
#include <cstdint>
namespace test_variant {
struct MyStructTag
{
uint32_t ver;
double kind;
std::string type;
};
typedef boost::variant<MyStructTag, std::string> myVariant;
struct custom_ostream : public boost::static_visitor<std::ostream&>
{
std::ostream& os_;
custom_ostream(std::ostream& os) : os_(os) {}
#if 1
template <typename T>
std::ostream& operator()(T const& val) const
{
return os_ << val;
}
#else
std::ostream& operator()(MyStructTag const& val) const
{
return os_ << val.type;
}
#endif
friend std::ostream& operator<<(std::ostream& os, myVariant const& v)
{
return boost::apply_visitor(custom_ostream{os}, v);
}
};
using namespace test_variant;
int main(int argc, char* agrv[])
{
myVariant my;
my = "test";
std::cout << my << std::endl;
return 0;
}
代码编译为:
g++ --std=c++11 -o main -Iv_1_55_0/ main.cpp
尝试挑出访问自定义有界类型,但没有成功。
任何输入都会有所帮助。
错误原因是operator<<(std::ostream& os, myVariant const& v)
没有通过ADL找到。
依赖于参数的查找是一个涉及扩展名称空间集的过程,这些名称空间在名称查找中被检查以查找不合格的函数调用,std::cout << my
就是一个例子。也就是说,您不拼写 std::cout.operator<<(my)
,也不拼写 std::operator<<(std::cout, my)
。
ADL 构建了一组 关联的命名空间 ,其中可以找到函数的名称(此处 operator<<
)。这些名称空间可以是,例如:
- 参数类型的命名空间,
- 参数类型的模板参数类型的命名空间。
operator<<
的参数是:
std::cout
,位于 std
命名空间,
boost::variant
,位于 boost
命名空间中。
除了这些命名空间之外,还考虑了模板参数的命名空间,它们是:
MyStructTag
,位于 test_variant
命名空间,
std::string
,位于 std
命名空间中。
最重要的是,ADL 考虑 关联 classes 作为 class 模板实例化的参数,这里是:
std::string
,
MyStructTag
.
此时,operator<<(std::ostream& os, myVariant const& v)
可以通过 ADL 找到,如果它是在内部声明的,例如 test_variant
命名空间本身。但是,该函数是在 custom_ostream
中声明和定义的,对于在 classes 中声明的 friend
函数,它们对 ADL 不可见,除非 class 是关联的 class。由于 custom_ostream
不在关联的 class 集合中,查找无法找到与调用参数匹配的 operator<<
重载。
为了解决这个问题,在 test_variant
命名空间本身中定义 operator<<
,在 custom_ostream
中只留下友元声明。
我正在试验 boost::variant 并使用标准类型打印,如下所示,有效。
typedef boost::variant<int, std::string> myVariant;
myVariant my;
my = "Hello";
std::cout << my << endl;
但是当我引入自定义类型时
struct MyStructTag
{
uint32_t ver;
double kind;
std::string type;
};
typedef boost::variant<MyStructTag, std::string> myVariant;
它抛出以下错误,但无法完全理解。
main.cpp: In instantiation of ‘std::ostream& test_variant::custom_ostream::operator()(const T&) const [with T = test_variant::MyStructTag; std::ostream = std::basic_ostream<char>]’:
v_1_55_0/boost/variant/variant.hpp:938:32: required from ‘boost::detail::variant::invoke_visitor<Visitor>::result_type boost::detail::variant::invoke_visitor<Visitor>::internal_visit(T&, int) [with T = const test_variant::MyStructTag; Visitor = const test_variant::custom_ostream; boost::detail::variant::invoke_visitor<Visitor>::result_type = std::basic_ostream<char>&]’
v_1_55_0/boost/variant/detail/visitation_impl.hpp:113:9: required 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<const test_variant::custom_ostream>; VoidPtrCV = const void*; T = test_variant::MyStructTag; typename Visitor::result_type = std::basic_ostream<char>&; mpl_::true_ = mpl_::bool_<true>]’
v_1_55_0/boost/variant/detail/visitation_impl.hpp:156:9: required from ‘typename Visitor::result_type boost::detail::variant::visitation_impl_invoke(int, Visitor&, VoidPtrCV, T*, NoBackupFlag, int) [with Visitor = boost::detail::variant::invoke_visitor<const test_variant::custom_ostream>; VoidPtrCV = const void*; T = test_variant::MyStructTag; NoBackupFlag = boost::variant<test_variant::MyStructTag, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::has_fallback_type_; typename Visitor::result_type = std::basic_ostream<char>&]’
v_1_55_0/boost/variant/detail/visitation_impl.hpp:237:5: required 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_<2l>, test_variant::MyStructTag, boost::mpl::l_item<mpl_::long_<1l>, std::basic_string<char>, boost::mpl::l_end> > >, boost::mpl::l_iter<boost::mpl::l_end> >; Visitor = boost::detail::variant::invoke_visitor<const test_variant::custom_ostream>; VoidPtrCV = const void*; NoBackupFlag = boost::variant<test_variant::MyStructTag, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::has_fallback_type_; typename Visitor::result_type = std::basic_ostream<char>&; mpl_::false_ = mpl_::bool_<false>]’
v_1_55_0/boost/variant/variant.hpp:2237:13: required from ‘static typename Visitor::result_type boost::variant<T0, TN>::internal_apply_visitor_impl(int, int, Visitor&, VoidPtrCV) [with Visitor = boost::detail::variant::invoke_visitor<const test_variant::custom_ostream>; VoidPtrCV = const void*; T0_ = test_variant::MyStructTag; TN = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; typename Visitor::result_type = std::basic_ostream<char>&]’
v_1_55_0/boost/variant/variant.hpp:2259:13: required from ‘typename Visitor::result_type boost::variant<T0, TN>::internal_apply_visitor(Visitor&) const [with Visitor = boost::detail::variant::invoke_visitor<const test_variant::custom_ostream>; T0_ = test_variant::MyStructTag; TN = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; typename Visitor::result_type = std::basic_ostream<char>&]’
v_1_55_0/boost/variant/variant.hpp:2281:52: required from ‘typename Visitor::result_type boost::variant<T0, TN>::apply_visitor(Visitor&) const [with Visitor = const test_variant::custom_ostream; T0_ = test_variant::MyStructTag; TN = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; typename Visitor::result_type = std::basic_ostream<char>&]’
v_1_55_0/boost/variant/detail/apply_visitor_unary.hpp:74:43: required from ‘typename Visitor::result_type boost::apply_visitor(const Visitor&, Visitable&) [with Visitor = test_variant::custom_ostream; Visitable = const boost::variant<test_variant::MyStructTag, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >; typename Visitor::result_type = std::basic_ostream<char>&]’
main.cpp:34:59: required from here
main.cpp:23:21: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
return os_ << val;
^
In file included from /usr/include/c++/4.8.2/iostream:39:0,
from main.cpp:1:
/usr/include/c++/4.8.2/ostream:602:5: error: initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = test_variant::MyStructTag]’
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
In file included from v_1_55_0/boost/variant/variant.hpp:2325:0,
from v_1_55_0/boost/variant.hpp:17,
from main.cpp:2:
v_1_55_0/boost/variant/detail/variant_io.hpp: In instantiation of ‘void boost::detail::variant::printer<OStream>::operator()(const T&) const [with T = test_variant::MyStructTag; OStream = std::basic_ostream<char>]’:
v_1_55_0/boost/variant/variant.hpp:938:32: required from ‘boost::detail::variant::invoke_visitor<Visitor>::result_type boost::detail::variant::invoke_visitor<Visitor>::internal_visit(T&, int) [with T = const test_variant::MyStructTag; Visitor = boost::detail::variant::printer<std::basic_ostream<char> >; boost::detail::variant::invoke_visitor<Visitor>::result_type = void]’
v_1_55_0/boost/variant/detail/visitation_impl.hpp:113:9: required 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 = test_variant::MyStructTag; typename Visitor::result_type = void; mpl_::true_ = mpl_::bool_<true>]’
v_1_55_0/boost/variant/detail/visitation_impl.hpp:156:9: required 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 = test_variant::MyStructTag; NoBackupFlag = boost::variant<test_variant::MyStructTag, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::has_fallback_type_; typename Visitor::result_type = void]’
v_1_55_0/boost/variant/detail/visitation_impl.hpp:237:5: required 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_<2l>, test_variant::MyStructTag, boost::mpl::l_item<mpl_::long_<1l>, std::basic_string<char>, 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<test_variant::MyStructTag, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::has_fallback_type_; typename Visitor::result_type = void; mpl_::false_ = mpl_::bool_<false>]’
v_1_55_0/boost/variant/variant.hpp:2237:13: required from ‘static typename Visitor::result_type boost::variant<T0, TN>::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_ = test_variant::MyStructTag; TN = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; typename Visitor::result_type = void]’
v_1_55_0/boost/variant/variant.hpp:2259:13: required from ‘typename Visitor::result_type boost::variant<T0, TN>::internal_apply_visitor(Visitor&) const [with Visitor = boost::detail::variant::invoke_visitor<boost::detail::variant::printer<std::basic_ostream<char> > >; T0_ = test_variant::MyStructTag; TN = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; typename Visitor::result_type = void]’
v_1_55_0/boost/variant/variant.hpp:2281:52: required from ‘typename Visitor::result_type boost::variant<T0, TN>::apply_visitor(Visitor&) const [with Visitor = boost::detail::variant::printer<std::basic_ostream<char> >; T0_ = test_variant::MyStructTag; TN = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; typename Visitor::result_type = void]’
v_1_55_0/boost/variant/detail/variant_io.hpp:88:5: required from ‘std::basic_ostream<_CharT, _Traits>& boost::operator<<(std::basic_ostream<_CharT, _Traits>&, const boost::variant<U0, UN ...>&) [with E = char; T = std::char_traits<char>; U0 = test_variant::MyStructTag; UN = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >}]’
main.cpp:47:17: required from here
v_1_55_0/boost/variant/detail/variant_io.hpp:64:14: error: cannot bind ‘std::basic_ostream<char>’ lvalue to ‘std::basic_ostream<char>&&’
out_ << operand;
完整代码
#include <iostream>
#include <boost/variant.hpp>
#include <cstdint>
namespace test_variant {
struct MyStructTag
{
uint32_t ver;
double kind;
std::string type;
};
typedef boost::variant<MyStructTag, std::string> myVariant;
struct custom_ostream : public boost::static_visitor<std::ostream&>
{
std::ostream& os_;
custom_ostream(std::ostream& os) : os_(os) {}
#if 1
template <typename T>
std::ostream& operator()(T const& val) const
{
return os_ << val;
}
#else
std::ostream& operator()(MyStructTag const& val) const
{
return os_ << val.type;
}
#endif
friend std::ostream& operator<<(std::ostream& os, myVariant const& v)
{
return boost::apply_visitor(custom_ostream{os}, v);
}
};
using namespace test_variant;
int main(int argc, char* agrv[])
{
myVariant my;
my = "test";
std::cout << my << std::endl;
return 0;
}
代码编译为:
g++ --std=c++11 -o main -Iv_1_55_0/ main.cpp
尝试挑出访问自定义有界类型,但没有成功。
任何输入都会有所帮助。
错误原因是operator<<(std::ostream& os, myVariant const& v)
没有通过ADL找到。
依赖于参数的查找是一个涉及扩展名称空间集的过程,这些名称空间在名称查找中被检查以查找不合格的函数调用,std::cout << my
就是一个例子。也就是说,您不拼写 std::cout.operator<<(my)
,也不拼写 std::operator<<(std::cout, my)
。
ADL 构建了一组 关联的命名空间 ,其中可以找到函数的名称(此处 operator<<
)。这些名称空间可以是,例如:
- 参数类型的命名空间,
- 参数类型的模板参数类型的命名空间。
operator<<
的参数是:
std::cout
,位于std
命名空间,boost::variant
,位于boost
命名空间中。
除了这些命名空间之外,还考虑了模板参数的命名空间,它们是:
MyStructTag
,位于test_variant
命名空间,std::string
,位于std
命名空间中。
最重要的是,ADL 考虑 关联 classes 作为 class 模板实例化的参数,这里是:
std::string
,MyStructTag
.
此时,operator<<(std::ostream& os, myVariant const& v)
可以通过 ADL 找到,如果它是在内部声明的,例如 test_variant
命名空间本身。但是,该函数是在 custom_ostream
中声明和定义的,对于在 classes 中声明的 friend
函数,它们对 ADL 不可见,除非 class 是关联的 class。由于 custom_ostream
不在关联的 class 集合中,查找无法找到与调用参数匹配的 operator<<
重载。
为了解决这个问题,在 test_variant
命名空间本身中定义 operator<<
,在 custom_ostream
中只留下友元声明。