簡體   English   中英

將虛擬功能融入家庭

[英]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";}
};

我想將foobar (以及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>看起來幾乎相同,並且理想情況下應該不進行專業化(特別是如果有許多其他虛擬函數,而不是foobar )。 寫類似:

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類。

這是我的嘗試。 我已經用用作標簽的struct替換了enum ,並用EnumTraitsTagTraits 我更喜歡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.

您不能將繼承和多態與模板元編程結合在一起。 您正在嘗試使用編譯時間機制來調用正確的函數。 盡管這是可能的,但您不能取消引用指針來調用正確的函數並期望它在編譯時運行。

從本質上講,您所做的就是在繼承層次結構中包裝部分模板專業化層次結構。 這有點令人困惑。 如果取消引用具有繼承層次結構的指針,則該調用將通過在虛擬表中進行查找來解決。

您也可以拉模板編譯時間調度,但這會有所不同。 您將需要使用SFINAE創建一個接口並從那里開始工作

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM