如何将 `boost::static_visitor` 实例传递给函数
How to pass `boost::static_visitor` instances to functions
我在我的项目中经常使用 boost::variant
。我的同事现在想出了传递特定 boost::static_visitor<int>
实例的想法,以便自定义访问类型。她有一些代码如下:
#include <boost/variant.hpp>
#include <iostream>
typedef boost::variant<int, std::string> TVar;
struct Visitor1 : public boost::static_visitor<int> {
template<typename T>
result_type operator()(const T&) {
return 42;
}
};
struct Visitor2 : public boost::static_visitor<int> {
template<typename T>
result_type operator()(const T&) {
return 21;
}
};
int adder(const boost::static_visitor<int>& visitor, const TVar& visitable) {
return visitable.apply_visitor(visitor) + 1;
}
int main(int argc, char **args) {
Visitor1 v1;
Visitor2 v2;
TVar x;
std::cout << adder(v1, x) << std::endl;
std::cout << adder(v2, x) << std::endl;
}
它对我来说看起来很完美,但它无法编译。我的编译器说 expression will not yield a function that takes one 1 argument
某处 insider 。
我们做错了什么?
apply_visitor
有一个只接受访问者的重载。这个returns一个适合你需要的部分应用函数对象,我猜:
这个重载returns一个
就个人而言,我喜欢像这样向访问者对象添加重载:
struct MyVisitor {
typedef void result_type;
template <typename... Ts>
result_type operator()(boost::variant<Ts...> const& v) const {
return boost::apply_visitor(*this, v);
}
// optionally repeat for non-const `v`
// normal variant handling overloads
};
这样,您可以简单地将访问者对象用作函数对象。
static_visitor
不是多态基 class,不能这样处理。顾名思义:它是一个 static(静态类型)访问者。您需要访问者的 static 类型成为您要调用的访问者。请注意,这是不可避免的,因为成员函数模板不能是虚拟的。在您的情况下,这意味着 adder
必须成为一个函数模板,由访问者类型模板化:
template <class Visitor>
int adder(const Visitor& visitor, const TVar& visitable) {
return visitable.apply_visitor(visitor) + 1;
}
在 main
中的使用将保持不变。
如果您无力制作 adder
模板,您可以使用 提到的 apply_visitor
结合 std::function
(或者 boost::function
如果你不能使用 C++11):
int adder(std::function<int(const TVar&)> visitorApplier, const TVar& visitable)
{
return visitorApplier(visitable);
}
int main(int argc, char **args) {
Visitor1 v1;
Visitor2 v2;
TVar x;
std::cout << adder(boost::apply_visitor(v1), x) << std::endl;
std::cout << adder(boost::apply_visitor(v2), x) << std::endl;
}
从技术上讲,访问者本身已经是一个合适的可调用对象,因此即使不显式使用它也应该可以工作 apply_visitor
:
int main(int argc, char **args) {
Visitor1 v1;
Visitor2 v2;
TVar x;
std::cout << adder(v1, x) << std::endl;
std::cout << adder(v2, x) << std::endl;
}
首先,您应该将访问者的 operator()
过载标记为 const
:
struct Visitor1 : public boost::static_visitor<int> {
template<typename T>
result_type operator()(const T&) const {
return 42;
}
};
struct Visitor2 : public boost::static_visitor<int> {
template<typename T>
result_type operator()(const T&) const {
return 21;
}
};
然后,您需要更改加法器以接受模板参数而不是 boost::static_visitor
- 这是您的 Visitor1
类型,其中包含具有您想要的逻辑的 operator()
重载。您需要 "correct type" 才能进行访问。
template <typename T>
int adder(const T& visitor, const TVar& visitable) {
return visitable.apply_visitor(visitor) + 1;
}
我在我的项目中经常使用 boost::variant
。我的同事现在想出了传递特定 boost::static_visitor<int>
实例的想法,以便自定义访问类型。她有一些代码如下:
#include <boost/variant.hpp>
#include <iostream>
typedef boost::variant<int, std::string> TVar;
struct Visitor1 : public boost::static_visitor<int> {
template<typename T>
result_type operator()(const T&) {
return 42;
}
};
struct Visitor2 : public boost::static_visitor<int> {
template<typename T>
result_type operator()(const T&) {
return 21;
}
};
int adder(const boost::static_visitor<int>& visitor, const TVar& visitable) {
return visitable.apply_visitor(visitor) + 1;
}
int main(int argc, char **args) {
Visitor1 v1;
Visitor2 v2;
TVar x;
std::cout << adder(v1, x) << std::endl;
std::cout << adder(v2, x) << std::endl;
}
它对我来说看起来很完美,但它无法编译。我的编译器说 expression will not yield a function that takes one 1 argument
某处 insider 。
我们做错了什么?
apply_visitor
有一个只接受访问者的重载。这个returns一个适合你需要的部分应用函数对象,我猜:
这个重载returns一个
就个人而言,我喜欢像这样向访问者对象添加重载:
struct MyVisitor {
typedef void result_type;
template <typename... Ts>
result_type operator()(boost::variant<Ts...> const& v) const {
return boost::apply_visitor(*this, v);
}
// optionally repeat for non-const `v`
// normal variant handling overloads
};
这样,您可以简单地将访问者对象用作函数对象。
static_visitor
不是多态基 class,不能这样处理。顾名思义:它是一个 static(静态类型)访问者。您需要访问者的 static 类型成为您要调用的访问者。请注意,这是不可避免的,因为成员函数模板不能是虚拟的。在您的情况下,这意味着 adder
必须成为一个函数模板,由访问者类型模板化:
template <class Visitor>
int adder(const Visitor& visitor, const TVar& visitable) {
return visitable.apply_visitor(visitor) + 1;
}
在 main
中的使用将保持不变。
如果您无力制作 adder
模板,您可以使用 apply_visitor
结合 std::function
(或者 boost::function
如果你不能使用 C++11):
int adder(std::function<int(const TVar&)> visitorApplier, const TVar& visitable)
{
return visitorApplier(visitable);
}
int main(int argc, char **args) {
Visitor1 v1;
Visitor2 v2;
TVar x;
std::cout << adder(boost::apply_visitor(v1), x) << std::endl;
std::cout << adder(boost::apply_visitor(v2), x) << std::endl;
}
从技术上讲,访问者本身已经是一个合适的可调用对象,因此即使不显式使用它也应该可以工作 apply_visitor
:
int main(int argc, char **args) {
Visitor1 v1;
Visitor2 v2;
TVar x;
std::cout << adder(v1, x) << std::endl;
std::cout << adder(v2, x) << std::endl;
}
首先,您应该将访问者的 operator()
过载标记为 const
:
struct Visitor1 : public boost::static_visitor<int> {
template<typename T>
result_type operator()(const T&) const {
return 42;
}
};
struct Visitor2 : public boost::static_visitor<int> {
template<typename T>
result_type operator()(const T&) const {
return 21;
}
};
然后,您需要更改加法器以接受模板参数而不是 boost::static_visitor
- 这是您的 Visitor1
类型,其中包含具有您想要的逻辑的 operator()
重载。您需要 "correct type" 才能进行访问。
template <typename T>
int adder(const T& visitor, const TVar& visitable) {
return visitable.apply_visitor(visitor) + 1;
}