将虚函数放入一个族中
Putting virtual functions into a family
给定
class A {
public:
virtual int foo (int) const = 0;
virtual void bar (char, double) const = 0;
};
class B : public A {
virtual int foo (int) const {std::cout << "B::foo() called.\n"; return 3;}
virtual void bar () const {std::cout << "B::bar() called.\n";}
};
class C : public B {
virtual int foo (int) const {std::cout << "C::foo() called.\n"; return 8;}
virtual void bar (char, double) const {std::cout << "C::bar() called.\n";}
};
我想将 foo
和 bar
(以及 A
的其他虚函数)放入函数模板族中。这是我到目前为止的想法:
#include <iostream>
enum Enum {Foo, Bar};
template <Enum> struct EnumTraits;
template <> struct EnumTraits<Foo> { using return_type = int; };
template <> struct EnumTraits<Bar> { using return_type = void; };
class A {
template <Enum> class Execute;
public:
virtual int foo (int) const = 0;
virtual void bar (char, double) const = 0;
template <Enum E, typename... Args>
typename EnumTraits<E>::return_type execute(Args&&... args) const {
return Execute<E>(this)(std::forward<Args>(args)...);
}
};
template <>
class A::Execute<Foo> {
const A* a;
public:
Execute (const A* a_) : a(a_) {}
template <typename... Args>
int operator()(Args&&... args) const {return a->foo(std::forward<Args>(args)...);}
};
template <>
class A::Execute<Bar> {
const A* a;
public:
Execute (const A* a_) : a(a_) {}
template <typename... Args>
void operator()(Args&&... args) const {a->bar(std::forward<Args>(args)...);}
};
class B : public A {
virtual int foo (int) const {std::cout << "B::foo() called.\n"; return 3;}
virtual void bar () const {std::cout << "B::bar() called.\n";}
};
class C : public B {
virtual int foo (int) const {std::cout << "C::foo() called.\n"; return 8;}
virtual void bar (char, double) const {std::cout << "C::bar() called.\n";}
};
int main() {
A* c = new C;
int n = c->foo(5); // C::foo() called.
c->bar(3, 'c'); // C::bar() called.
n = c->execute<Foo>(5); // C::foo() called.
c->execute<Bar>(3, 'c'); // C::bar() called.
}
但是特化 A::Execute<Foo>
和 A::Execute<Bar>
看起来几乎相同,理想情况下应该不特化(特别是如果除了 foo
和 bar
还有许多其他虚函数).写成这样:
template <Enum N>
class A::Execute {
const A* a;
public:
Execute (const A* a_) : a(a_) {}
template <typename... Args>
int operator()(Args&&... args) const {return a->???(std::forward<Args>(args)...);}
};
怎么填写???部分?理想情况下,我希望使用已经存在的 EnumTraits
class。
您不能将继承和多态性与模板元编程相结合。您要做的是使用编译时机制来调用正确的函数。虽然这是可能的,但您不能取消引用指针来调用正确的函数并期望它在编译时变为 运行 。
本质上,您所做的是在继承层次结构中包装部分模板专业化的层次结构。这有点令人困惑。如果您取消引用具有继承层次结构的指针,则调用将通过在虚拟 table 中查找来解析。
您也可以提取模板编译时分派,但这会有点不同。您需要使用 SFINAE 创建界面并从那里开始工作
这是我的尝试。我已经将 enum
替换为用作标签的 struct
,将 EnumTraits
替换为 TagTraits
。我更喜欢 struct
方法,因为它允许在不影响现有标签的情况下添加新标签。
#include <iostream>
#include <functional>
template <typename T> struct TagTraits;
// Generic implementation of A based on TagTraits.
class A {
template <typename Tag, typename... Args>
class Execute {
const A* a;
public:
Execute (const A* a_) : a(a_) {}
typename TagTraits<Tag>::return_type operator()(Args&&... args) const
{
return (a->*(TagTraits<Tag>::get_funtion_ptr()))(std::forward<Args>(args)...);
}
};
public:
virtual int foo (int) const = 0;
virtual void bar (char, double) const = 0;
template <typename Tag, typename... Args>
typename TagTraits<Tag>::return_type execute(Args&&... args) const
{
return Execute<Tag, Args...>(this)(std::forward<Args>(args)...);
}
};
// tag for foo and the corresponding TagTraits
struct foo_tag {};
template <> struct TagTraits<foo_tag>
{
using return_type = int;
static decltype(&A::foo) get_funtion_ptr(){ return &A::foo;}
};
// tag for bar and the corresponding TagTraits
struct bar_tag {};
template <> struct TagTraits<bar_tag>
{
using return_type = void;
static decltype(&A::bar) get_funtion_ptr(){ return &A::bar;}
};
// Derived classes of A.
class B : public A {
virtual int foo (int) const {std::cout << "B::foo() called.\n"; return 3;}
virtual void bar (char, double) const {std::cout << "B::bar() called.\n";}
};
class C : public B {
virtual int foo (int) const {std::cout << "C::foo() called.\n"; return 8;}
virtual void bar (char, double) const {std::cout << "C::bar() called.\n";}
};
// Test B
void test_B()
{
A* aPtr = new B;
int n = aPtr->foo(5); // B::foo() called.
aPtr->bar(3, 'c'); // B::bar() called.
n = aPtr->execute<foo_tag>(5); // B::foo() called.
aPtr->execute<bar_tag>(3, 'c'); // B::bar() called.
}
// Test C
void test_C()
{
A* aPtr = new C;
int n = aPtr->foo(5); // C::foo() called.
aPtr->bar(3, 'c'); // C::bar() called.
n = aPtr->execute<foo_tag>(5); // C::foo() called.
aPtr->execute<bar_tag>(3, 'c'); // C::bar() called.
}
int main()
{
test_B();
test_C();
}
输出:
B::foo() called.
B::bar() called.
B::foo() called.
B::bar() called.
C::foo() called.
C::bar() called.
C::foo() called.
C::bar() called.
给定
class A {
public:
virtual int foo (int) const = 0;
virtual void bar (char, double) const = 0;
};
class B : public A {
virtual int foo (int) const {std::cout << "B::foo() called.\n"; return 3;}
virtual void bar () const {std::cout << "B::bar() called.\n";}
};
class C : public B {
virtual int foo (int) const {std::cout << "C::foo() called.\n"; return 8;}
virtual void bar (char, double) const {std::cout << "C::bar() called.\n";}
};
我想将 foo
和 bar
(以及 A
的其他虚函数)放入函数模板族中。这是我到目前为止的想法:
#include <iostream>
enum Enum {Foo, Bar};
template <Enum> struct EnumTraits;
template <> struct EnumTraits<Foo> { using return_type = int; };
template <> struct EnumTraits<Bar> { using return_type = void; };
class A {
template <Enum> class Execute;
public:
virtual int foo (int) const = 0;
virtual void bar (char, double) const = 0;
template <Enum E, typename... Args>
typename EnumTraits<E>::return_type execute(Args&&... args) const {
return Execute<E>(this)(std::forward<Args>(args)...);
}
};
template <>
class A::Execute<Foo> {
const A* a;
public:
Execute (const A* a_) : a(a_) {}
template <typename... Args>
int operator()(Args&&... args) const {return a->foo(std::forward<Args>(args)...);}
};
template <>
class A::Execute<Bar> {
const A* a;
public:
Execute (const A* a_) : a(a_) {}
template <typename... Args>
void operator()(Args&&... args) const {a->bar(std::forward<Args>(args)...);}
};
class B : public A {
virtual int foo (int) const {std::cout << "B::foo() called.\n"; return 3;}
virtual void bar () const {std::cout << "B::bar() called.\n";}
};
class C : public B {
virtual int foo (int) const {std::cout << "C::foo() called.\n"; return 8;}
virtual void bar (char, double) const {std::cout << "C::bar() called.\n";}
};
int main() {
A* c = new C;
int n = c->foo(5); // C::foo() called.
c->bar(3, 'c'); // C::bar() called.
n = c->execute<Foo>(5); // C::foo() called.
c->execute<Bar>(3, 'c'); // C::bar() called.
}
但是特化 A::Execute<Foo>
和 A::Execute<Bar>
看起来几乎相同,理想情况下应该不特化(特别是如果除了 foo
和 bar
还有许多其他虚函数).写成这样:
template <Enum N>
class A::Execute {
const A* a;
public:
Execute (const A* a_) : a(a_) {}
template <typename... Args>
int operator()(Args&&... args) const {return a->???(std::forward<Args>(args)...);}
};
怎么填写???部分?理想情况下,我希望使用已经存在的 EnumTraits
class。
您不能将继承和多态性与模板元编程相结合。您要做的是使用编译时机制来调用正确的函数。虽然这是可能的,但您不能取消引用指针来调用正确的函数并期望它在编译时变为 运行 。
本质上,您所做的是在继承层次结构中包装部分模板专业化的层次结构。这有点令人困惑。如果您取消引用具有继承层次结构的指针,则调用将通过在虚拟 table 中查找来解析。
您也可以提取模板编译时分派,但这会有点不同。您需要使用 SFINAE 创建界面并从那里开始工作
这是我的尝试。我已经将 enum
替换为用作标签的 struct
,将 EnumTraits
替换为 TagTraits
。我更喜欢 struct
方法,因为它允许在不影响现有标签的情况下添加新标签。
#include <iostream>
#include <functional>
template <typename T> struct TagTraits;
// Generic implementation of A based on TagTraits.
class A {
template <typename Tag, typename... Args>
class Execute {
const A* a;
public:
Execute (const A* a_) : a(a_) {}
typename TagTraits<Tag>::return_type operator()(Args&&... args) const
{
return (a->*(TagTraits<Tag>::get_funtion_ptr()))(std::forward<Args>(args)...);
}
};
public:
virtual int foo (int) const = 0;
virtual void bar (char, double) const = 0;
template <typename Tag, typename... Args>
typename TagTraits<Tag>::return_type execute(Args&&... args) const
{
return Execute<Tag, Args...>(this)(std::forward<Args>(args)...);
}
};
// tag for foo and the corresponding TagTraits
struct foo_tag {};
template <> struct TagTraits<foo_tag>
{
using return_type = int;
static decltype(&A::foo) get_funtion_ptr(){ return &A::foo;}
};
// tag for bar and the corresponding TagTraits
struct bar_tag {};
template <> struct TagTraits<bar_tag>
{
using return_type = void;
static decltype(&A::bar) get_funtion_ptr(){ return &A::bar;}
};
// Derived classes of A.
class B : public A {
virtual int foo (int) const {std::cout << "B::foo() called.\n"; return 3;}
virtual void bar (char, double) const {std::cout << "B::bar() called.\n";}
};
class C : public B {
virtual int foo (int) const {std::cout << "C::foo() called.\n"; return 8;}
virtual void bar (char, double) const {std::cout << "C::bar() called.\n";}
};
// Test B
void test_B()
{
A* aPtr = new B;
int n = aPtr->foo(5); // B::foo() called.
aPtr->bar(3, 'c'); // B::bar() called.
n = aPtr->execute<foo_tag>(5); // B::foo() called.
aPtr->execute<bar_tag>(3, 'c'); // B::bar() called.
}
// Test C
void test_C()
{
A* aPtr = new C;
int n = aPtr->foo(5); // C::foo() called.
aPtr->bar(3, 'c'); // C::bar() called.
n = aPtr->execute<foo_tag>(5); // C::foo() called.
aPtr->execute<bar_tag>(3, 'c'); // C::bar() called.
}
int main()
{
test_B();
test_C();
}
输出:
B::foo() called.
B::bar() called.
B::foo() called.
B::bar() called.
C::foo() called.
C::bar() called.
C::foo() called.
C::bar() called.