2015-03-19 144 views
2

我想实现一个模板类,该模板类既可用作派生基础,又可用作具体类,如果模板参数是正确的。C++类模板或纯虚拟

我想要实现的是,如果模板类的方法不能被实例化,但派生类提供了一个实现,这是行。 但是,如果模板可以完全实例化,那么这个类自己就是有效的。

例子:

// interface class 
class A 
{ 
public: 
    virtual void foo() = 0; 
    virtual ~A() {} 
}; 

// template class 
template <typename T> 
class B : public A 
{ 
public: 
    /* if this tenplate can be instantiated */ 
    foo() 
    { 
     T obj; 
     std::cout << obj; 
    } 
    /* else 
    foo() = 0; 
    */ 
}; 

// concrete classes 
// will work on it's own 
typedef B<std::string> C; 

class D : public B<void> 
{ 
    // B<void>::foo won't instantiate on it's own 
    // so we provide help here 
    foo() {} 
}; 

int main(int argc, char const *argv[]) 
{ 
    A * = new C(); // all good 
    A * = new D(); // error: cannot instantiate B<void>::foo 
    return 0; 
} 

有没有办法实现这样的效果呢?

+1

你可能对sfinae有一些好运..看看std :: enable_if(或boost :: enable_if) – Pete 2015-03-19 12:25:02

+0

另一种选择是提供专业化的B Pete 2015-03-19 12:25:59

回答

3

使用SFINAE,你可以这样做:

namespace detail 
{ 
    // an helper for traits 
    template <typename T> 
    decltype(T{}, std::cout << T{}, std::true_type{}) 
    helper_has_default_constructor_and_foo(int); 

    template <typename T> 
    std::false_type helper_has_default_constructor_and_foo(...); 

    // the traits 
    template <typename T> 
    using has_default_constructor_and_foo = decltype(helper_has_default_constructor_and_foo<T>(0)); 

    // genaral case (so when traits is false) 
    template <typename T, typename = has_default_constructor_and_foo<T>> 
    struct C : public A {}; 

    // specialization when traits is true 
    template <typename T> 
    struct C<T, std::true_type> : public A 
    { 
     void foo() override { std::cout << T{}; } 
    }; 

} 

最后:

template <typename T> 
class B : public detail::C<T> 
{ 
}; 

live demo

0

你可以专门为B<void>

// template class 
template <typename T> 
class B : public A 
{ 
public: 
    virtual void foo() 
    { 
     T obj; 
     std::cout << obj; 
    } 
}; 
template <> 
class B<void> : public A 
{ 
public: 
    virtual void foo() = 0; 
}; 
0

必须专门B<>而不能使用SFINAE(成员foo上)。 SFINAE仅适用于模板,但成员函数模板不能为virtual

有可以实现专业化不同的方式,但最直接的方式是简单而明确的

template<typename T> 
class B : public A 
{ 
    /* ... */    // not overridden foo() by default 
}; 

template<> 
class B<WhatEver> : public A 
{ 
    virtual foo(); 
};