2010-06-30 68 views
0

我在類C中有一個方法foo,它可以調用foo_1或foo_2。 該方法foo()具有在C被定義,因爲FOO()是純在BaseClass的虛擬和我實際上 必須進行以下類型C.代碼的對象:C++模板實例化限制

template <class T> 
class C:public BaseClass{ 

    void foo() { 
    if (something()) foo_1; 
    else foo_2; 

    } 
    void foo_1() { 
    .... 
    } 

    void foo_2() { 
    .... 
    T t; 
    t.bar(); // requires class T to provide a method bar() 
    .... 
    } 
}; 

現在大多數類型ŤFOO_1將足夠,但對於某些類型foo_2將被稱爲 (取決於())。然而,編譯器堅持要實例化foo_1 和foo_2,因爲可能會調用它們。

這給T帶來了負擔,它必須提供條形方法 。

我如何告訴編譯如下:

  • 如果T沒有吧(),仍然允許它作爲一個實體化類型?
+0

我的意思是foo()在BaseClass中是純虛擬的。 – user231536 2010-06-30 17:43:42

+1

@andand他的班名是'C'。我不認爲他指的是C語言。 – stinky472 2010-06-30 17:44:00

+2

什麼是'something()'?它是否有一些編譯時常量? – 2010-06-30 17:48:12

回答

1

您可以使用boost.enable_if。是這樣的:

#include <boost/utility/enable_if.hpp> 
#include <iostream> 

struct T1 { 
    static const bool has_bar = true; 
    void bar() { std::cout << "bar" << std::endl; } 
}; 

struct T2 { 
    static const bool has_bar = false; 
}; 

struct BaseClass {}; 

template <class T> 
class C: public BaseClass { 
public: 
    void foo() { 
     do_foo<T>(); 
    } 

    void foo_1() { 
     // .... 
    } 

    template <class U> 
    void foo_2(typename boost::enable_if_c<U::has_bar>::type* = 0) { 
     // .... 
     T t; 
     t.bar(); // requires class T to provide a method bar() 
     // .... 
    } 

private: 

    bool something() const { return false; } 


    template <class U> 
    void do_foo(typename boost::enable_if_c<U::has_bar>::type* = 0) { 
     if (something()) foo_1(); 
     else foo_2<U>(); 
    } 

    template <class U> 
    void do_foo(typename boost::disable_if_c<U::has_bar>::type* = 0) { 
     if (something()) foo_1(); 
     // I dunno what you want to happen if there is no T::bar() 
    } 
}; 

int main() { 
    C<T1> c; 
    c.foo(); 
} 
+0

我們可以做到這一點,而不使用提升? – user231536 2010-06-30 17:54:01

+0

請參閱http://stackoverflow.com/questions/2937425/boostenable-if-class-template-method/2937522#2937522 - 你需要templatize「do_foo」 – 2010-06-30 17:54:22

+0

你是對的,我正在尋求適當的解決方案: - )。 – 2010-06-30 17:58:58

0

您可以爲FOO_1和FOO_2創建一個接口,如:


class IFoo 
{ 
public: 
    virtual void foo_1()=0; 
    virtual void foo_2()=0; 
}; 

template <typename T> 
class C : public BaseClass, public IFoo 
{ 

    void foo() 
    { 
    if (something()) 
     foo_1(); 
    else 
     foo_2(); 
    } 
}; 

template <typename T> 
class DerivedWithBar : C<T> 
{ 
public: 
    void foo_1() { ... } 

    void foo_2() 
    { 
     ... 
     T t; 
     t.bar(); // requires class T to provide a method bar() 
     ... 
    } 
}; 

template <typename T> 
class DerivedNoBar : C<T> 
{ 
public: 
    void foo_1() { ... } 
    void foo_2() { ... } 
}; 
0

我認爲最簡單的方法是簡單地寫一個單獨的函數模板「C」可以調用:

template <class T> 
void call_bar(T& /*t*/) 
{ 
} 

template <> 
void call_bar<Something>(Something& t) 
{ 
    t.bar(); 
} 

原始 'C' 類可以被相應地修改:

void foo_2() { 
    .... 
    T t; 
    call_bar(t); // does not require T to provide bar() 
    .... 
} 

這有缺點,你必須明確定義哪些類型的T提供了一個bar方法,但這幾乎是不可避免的,除非你可以在編譯時確定一些關於在其公共接口中提供bar方法的所有類型的東西或者修改所有這些條形支撐類型,以便它們共享可以在編譯時確定的共同事物。

+1

「這有一個缺點,你必須明確定義哪種類型的T提供了一個bar方法,但這幾乎是不可避免的,除非你可以在編譯時確定在公共接口中提供一個bar方法的所有類型的東西」你可以強迫所有人在他們的公共界面中定義這樣一個功能。 ADL [尊重和發現](http://www.gotw.ca/publications/mill02。htm)在這些類型的命名空間中定義的函數。請參閱解釋「接口原則」的鏈接。如果我想用一個免費的功能,我會將它基於ADL。 – 2010-06-30 18:09:56

+0

@Johannes根據OP的說法,something()不是可以在運行時評估的表達式。如果沒有更多的上下文信息,我們不得不假設調用foo_1和foo_2(期望欄的代碼)的代碼將針對所有類型生成。T我們如何利用ADL來處理這種情況?有一個函數call_bar,它不會在調用bar的單獨命名空間中調用bar,將bar中的類型放在不同的命名空間中,並依賴於ADL來調用正確的版本? – stinky472 2010-06-30 23:11:26