使用额外参数提升变体访问者
Boost variant visitor with an extra parameter
我有类似于下面的代码。
typedef uint32_t IntType;
typedef IntType IntValue;
typedef boost::variant<IntValue, std::string> MsgValue;
MsgValue v;
而不是说这个,
IntValue value = boost::apply_visitor(d_string_int_visitor(), v);
我想像这样传递一个额外的参数: 但是 operator() 给出了编译错误。
//This gives an error since the overload below doesn't work.
IntValue value = boost::apply_visitor(d_string_int_visitor(), v, anotherStr);
class d_string_int_visitor : public boost::static_visitor<IntType>
{
public:
inline IntType operator()(IntType i) const
{
return i;
}
inline IntValue operator()(const std::string& str) const noexcept
{
// code in here
}
//I want this, but compiler error.
inline IntValue operator()(const std::string& str, const std::string s) const noexcept
{
// code in here
}
};
您可以使用 std::bind
将额外的 string
参数绑定到访问者。首先,将 std::string
参数添加到访问者的所有 operator()
重载。
class d_string_int_visitor : public boost::static_visitor<IntType>
{
public:
inline IntType operator()(IntType i, const std::string& s) const
{
return i;
}
inline IntValue operator()(const std::string& str, const std::string& s) const noexcept
{
// code in here
return 0;
}
};
现在创建一个已绑定第二个 string
参数的访问者。
auto bound_visitor = std::bind(d_string_int_visitor(), std::placeholders::_1, "Hello World!");
boost::apply_visitor(bound_visitor, v);
但是,更好的解决方案是将字符串作为访问者的构造函数参数传递。
typedef uint32_t IntType;
typedef IntType IntValue;
typedef boost::variant<IntValue, std::string> MsgValue;
MsgValue v;
IntValue value = boost::apply_visitor([&](auto&& one){
return d_string_int_visitor{}(decltype(one)(one), anotherStr);
}, v);
假设 d_string_int_visitor
的每个重载都可以处理额外的参数。
作为奖励,如果需要,您甚至可以取消包装 class:
IntValue to_int_value(IntValue v, std::string const& format) { return v; }
IntValue to_int_value(std::string const& str, std::string const& format);
IntValue value = boost::apply_visitor([&](auto&& one){
return to_int_value(decltype(one)(one), anotherStr);
}, v);
我们在这里创建一个匿名 lambda,转发给一组传统的函数重载。
auto&& one
和 decltype(one)(one)
是一种从 lambda (C++14) 进行完美转发的技术。您可以将第二个替换为 std::forward<decltype(one)>(one)
,但我发现简短版本可读。与 std::forward
不同,它对值类型执行 "wrong" 操作,但我们知道 one
是 l 或 r 值引用。
我有类似于下面的代码。
typedef uint32_t IntType;
typedef IntType IntValue;
typedef boost::variant<IntValue, std::string> MsgValue;
MsgValue v;
而不是说这个,
IntValue value = boost::apply_visitor(d_string_int_visitor(), v);
我想像这样传递一个额外的参数: 但是 operator() 给出了编译错误。
//This gives an error since the overload below doesn't work.
IntValue value = boost::apply_visitor(d_string_int_visitor(), v, anotherStr);
class d_string_int_visitor : public boost::static_visitor<IntType>
{
public:
inline IntType operator()(IntType i) const
{
return i;
}
inline IntValue operator()(const std::string& str) const noexcept
{
// code in here
}
//I want this, but compiler error.
inline IntValue operator()(const std::string& str, const std::string s) const noexcept
{
// code in here
}
};
您可以使用 std::bind
将额外的 string
参数绑定到访问者。首先,将 std::string
参数添加到访问者的所有 operator()
重载。
class d_string_int_visitor : public boost::static_visitor<IntType>
{
public:
inline IntType operator()(IntType i, const std::string& s) const
{
return i;
}
inline IntValue operator()(const std::string& str, const std::string& s) const noexcept
{
// code in here
return 0;
}
};
现在创建一个已绑定第二个 string
参数的访问者。
auto bound_visitor = std::bind(d_string_int_visitor(), std::placeholders::_1, "Hello World!");
boost::apply_visitor(bound_visitor, v);
但是,更好的解决方案是将字符串作为访问者的构造函数参数传递。
typedef uint32_t IntType;
typedef IntType IntValue;
typedef boost::variant<IntValue, std::string> MsgValue;
MsgValue v;
IntValue value = boost::apply_visitor([&](auto&& one){
return d_string_int_visitor{}(decltype(one)(one), anotherStr);
}, v);
假设 d_string_int_visitor
的每个重载都可以处理额外的参数。
作为奖励,如果需要,您甚至可以取消包装 class:
IntValue to_int_value(IntValue v, std::string const& format) { return v; }
IntValue to_int_value(std::string const& str, std::string const& format);
IntValue value = boost::apply_visitor([&](auto&& one){
return to_int_value(decltype(one)(one), anotherStr);
}, v);
我们在这里创建一个匿名 lambda,转发给一组传统的函数重载。
auto&& one
和 decltype(one)(one)
是一种从 lambda (C++14) 进行完美转发的技术。您可以将第二个替换为 std::forward<decltype(one)>(one)
,但我发现简短版本可读。与 std::forward
不同,它对值类型执行 "wrong" 操作,但我们知道 one
是 l 或 r 值引用。