2010-06-30 71 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