隐藏重载虚函数的模板化访问者:使用 SFINAE?
Templated visitor that hides overloaded virtual function : SFINAE on using?
我正在写一个访问者模板化(取决于我们要访问的类型):
#include <iostream>
#include <memory>
#include <vector>
#include <string>
class INode;
class INodeVisitor {
public:
virtual void visit(INode&) = 0;
virtual ~INodeVisitor() = default;
};
template<typename ...Ts>
class TypedNodeVisitor;
template<typename T1, typename ...Ts>
class TypedNodeVisitor<T1, Ts...> : public TypedNodeVisitor<Ts...> {
public:
virtual void visit(INode &v) override {
if(auto p = dynamic_cast<T1*>(std::addressof(v))) {
apply(*p);
}
if constexpr(sizeof...(Ts) != 0) {
TypedNodeVisitor<Ts...>::visit(v);
}
}
//using TypedNodeVisitor<Ts...>::apply;
virtual void apply(T1 &) = 0;
};
template<>
class TypedNodeVisitor<> : public INodeVisitor {};
class INode {
public:
void accept(INodeVisitor &nv) {
nv.visit(*this);
}
virtual ~INode() = default;
};
class NodeB : public INode {};
class NodeA : public INode {};
class DrawerVisitor : public TypedNodeVisitor<NodeA, NodeB> {
public:
void apply(NodeA &) override {
std::cout << "A" << std::endl;
}
void apply(NodeB &) override {
std::cout << "B" << std::endl;
}
};
int main()
{
auto nodeA = std::make_shared<NodeA>();
auto nodeB = std::make_shared<NodeB>();
DrawerVisitor visitor;
nodeA->accept(visitor);
nodeB->accept(visitor);
return 0;
}
使用 clang 我收到这些警告:
prog.cc:49:30: note: in instantiation of template class 'TypedNodeVisitor<NodeA, NodeB>' requested here
class DrawerVisitor : public TypedNodeVisitor<NodeA, NodeB> {
^
prog.cc:31:18: note: hidden overloaded virtual function 'TypedNodeVisitor<NodeB>::apply' declared here: type mismatch at 1st parameter ('NodeB &' vs 'NodeA &')
virtual void apply(T1 &) = 0;
我明白问题出在哪里,但如果不在 TypedNodeVisitor<>
.
的空特化中添加 apply()
的伪定义,我无法解决它
有没有办法在 using TypedNodeVisitor<Ts...>::apply
上使用 std::enable_if
?
Is there a way to use enable_if on the using TypedNodeVisitor<Ts...>::apply
?
据我所知,你不能:你不能模板化那种类型的 using
所以你可以使用 SFINAE 来 enable/disable 它。
我认为定义 "faked definition of apply in the empty specialization of TypedNodeVisitor<>
" 没有任何问题(恕我直言,这是一个简单而优雅的解决方案)但是......如果你真的想避免它,你可以定义一个 TypedNodeVisitor<T0>
专业化,而不是TypedNodeVisitor<>
,如下
template <typename T0>
class TypedNodeVisitor<T0> : public INodeVisitor
{
public:
virtual void visit(INode &v) override {
if(auto p = dynamic_cast<T0*>(std::addressof(v))) {
apply(*p);
}
}
virtual void apply(T0 &) = 0;
};
这样你也可以避免在visit()
成员中进行if constexpr
测试(但是你可以避免在TypedNodeVisitor<>
中添加一个假的visit()
)
template<class...Ts>
struct IApply{};
template<class T0, class T1, class...Ts>
struct IApply<T0,T1,Ts...>:
IApply<T0>,IApply<T1,Ts...>
{
using IApply<T0>::apply;
using IApply<T1,Ts...>::apply;
};
template<class T0>
struct IApply<T0>{
virtual void apply(T0&)=0;
};
接下来执行此操作:
template<class Base, typename ...Ts>
class TypedNodeVisitor:public Base{};// 0 case
template<class Base, typename T1, typename ...Ts>
class TypedNodeVisitor<Base, T1, Ts...>: public TypedNodeVisitor<Base, Ts...> {
现在我们可以自定义我们的基地了。
template<class...Ts>
struct IBase: INodeVisitor, IApply<Ts...>{};
template<class...Ts>
struct ITypeNodeVisitor:TyoedNodeVisitor<IBase<Ts...>,Ts...>{};
class DrawerVisitor : public ITypedNodeVisitor<NodeA, NodeB> {
完成。
同时从 TypedNodeVisitor 中删除应用。
我正在写一个访问者模板化(取决于我们要访问的类型):
#include <iostream>
#include <memory>
#include <vector>
#include <string>
class INode;
class INodeVisitor {
public:
virtual void visit(INode&) = 0;
virtual ~INodeVisitor() = default;
};
template<typename ...Ts>
class TypedNodeVisitor;
template<typename T1, typename ...Ts>
class TypedNodeVisitor<T1, Ts...> : public TypedNodeVisitor<Ts...> {
public:
virtual void visit(INode &v) override {
if(auto p = dynamic_cast<T1*>(std::addressof(v))) {
apply(*p);
}
if constexpr(sizeof...(Ts) != 0) {
TypedNodeVisitor<Ts...>::visit(v);
}
}
//using TypedNodeVisitor<Ts...>::apply;
virtual void apply(T1 &) = 0;
};
template<>
class TypedNodeVisitor<> : public INodeVisitor {};
class INode {
public:
void accept(INodeVisitor &nv) {
nv.visit(*this);
}
virtual ~INode() = default;
};
class NodeB : public INode {};
class NodeA : public INode {};
class DrawerVisitor : public TypedNodeVisitor<NodeA, NodeB> {
public:
void apply(NodeA &) override {
std::cout << "A" << std::endl;
}
void apply(NodeB &) override {
std::cout << "B" << std::endl;
}
};
int main()
{
auto nodeA = std::make_shared<NodeA>();
auto nodeB = std::make_shared<NodeB>();
DrawerVisitor visitor;
nodeA->accept(visitor);
nodeB->accept(visitor);
return 0;
}
使用 clang 我收到这些警告:
prog.cc:49:30: note: in instantiation of template class 'TypedNodeVisitor<NodeA, NodeB>' requested here
class DrawerVisitor : public TypedNodeVisitor<NodeA, NodeB> {
^
prog.cc:31:18: note: hidden overloaded virtual function 'TypedNodeVisitor<NodeB>::apply' declared here: type mismatch at 1st parameter ('NodeB &' vs 'NodeA &')
virtual void apply(T1 &) = 0;
我明白问题出在哪里,但如果不在 TypedNodeVisitor<>
.
apply()
的伪定义,我无法解决它
有没有办法在 using TypedNodeVisitor<Ts...>::apply
上使用 std::enable_if
?
Is there a way to use enable_if on the using
TypedNodeVisitor<Ts...>::apply
?
据我所知,你不能:你不能模板化那种类型的 using
所以你可以使用 SFINAE 来 enable/disable 它。
我认为定义 "faked definition of apply in the empty specialization of TypedNodeVisitor<>
" 没有任何问题(恕我直言,这是一个简单而优雅的解决方案)但是......如果你真的想避免它,你可以定义一个 TypedNodeVisitor<T0>
专业化,而不是TypedNodeVisitor<>
,如下
template <typename T0>
class TypedNodeVisitor<T0> : public INodeVisitor
{
public:
virtual void visit(INode &v) override {
if(auto p = dynamic_cast<T0*>(std::addressof(v))) {
apply(*p);
}
}
virtual void apply(T0 &) = 0;
};
这样你也可以避免在visit()
成员中进行if constexpr
测试(但是你可以避免在TypedNodeVisitor<>
中添加一个假的visit()
)
template<class...Ts>
struct IApply{};
template<class T0, class T1, class...Ts>
struct IApply<T0,T1,Ts...>:
IApply<T0>,IApply<T1,Ts...>
{
using IApply<T0>::apply;
using IApply<T1,Ts...>::apply;
};
template<class T0>
struct IApply<T0>{
virtual void apply(T0&)=0;
};
接下来执行此操作:
template<class Base, typename ...Ts>
class TypedNodeVisitor:public Base{};// 0 case
template<class Base, typename T1, typename ...Ts>
class TypedNodeVisitor<Base, T1, Ts...>: public TypedNodeVisitor<Base, Ts...> {
现在我们可以自定义我们的基地了。
template<class...Ts>
struct IBase: INodeVisitor, IApply<Ts...>{};
template<class...Ts>
struct ITypeNodeVisitor:TyoedNodeVisitor<IBase<Ts...>,Ts...>{};
class DrawerVisitor : public ITypedNodeVisitor<NodeA, NodeB> {
完成。
同时从 TypedNodeVisitor 中删除应用。