调整模板提供的基类

时间:2016-02-18 20:22:09

标签: c++ c++11

如果基类不提供方法,您将如何填写方法?如果提供了基类方法,我想重用它。

E.g:

#include <iostream>
struct Base0 { };
struct Base1 { void m() { std::cout<<"Base1\n"; } };

template<typename T>
struct Derived : public T {
  //if T doesn't provide m, define it here, otherwise reuse the base class method 
  void m(){ /*? std::cout<<"Derived\n"; ?*/ }
};

int main(){
  Derived<Base0> d0;
  d0.m(); //should print "Derived"
  Derived<Base1> d1;
  d1.m(); //should print "Base1"
}

3 个答案:

答案 0 :(得分:8)

使用SFINAE,您可以

template<typename T>
struct Derived : public T {
private:
  template <typename U = T>
  auto m_impl(int) -> decltype(std::declval<U&>().m()){ this->U::m(); }

  template <typename U = T>
  void m_impl(... ) { std::cout<<"Derived\n"; }

public:
  void m() { m_impl(0); }
};

Demo

答案 1 :(得分:2)

为了保持一般性,您应该在不同的签名下定义该功能:

template<typename T>
struct Derived : public T
{
     auto m(std::false_type) { std::cout<<"Derived\n"; }
};

然后你可以使用this thread中给出的方法来检查基类是否具有函数m()

template <typename...>
using void_t = void;

template <typename T, template <typename> class D, typename = void>
struct detect : std::false_type {};

template <typename T, template <typename> class D>
struct detect<T, D, void_t<D<T>>> : std::true_type {};

template <typename T>
using has_m = decltype(std::declval<T>().m());

最后,您可以将其用作

template<typename T>
struct Derived : public T
{
     auto m(std::true_type) { return T::m(); }
     auto m(std::false_type) { std::cout<<"Derived\n"; }
     auto m() { return m(detect</* const */ T, has_m>{}); }
                                ^^^^^^^^^^
                                //if m() is const
};

DEMO

答案 2 :(得分:0)

Aslay Berby已经说过这可能不是你想去的方式。如果您想实现类似traits或基于策略的设计,下面的代码可能就是您要寻找的。事实上,这种设计很常用,也具有惯用价值。

#include <iostream>
using namespace std;

struct StandardTraits {void foo() {cout << "standard" << endl;}};

struct Traits1 {void foo() {cout << "traits1" << endl;}};
struct Traits2 {void foo() {cout << "traits2"<< endl;}};

template<typename T = StandardTraits>
class SomeClass
{
public:
    typedef T Traits;

    void useTraits() {traits.foo();}

private:
    Traits traits;
};

int main() {

    SomeClass<> x;
    SomeClass<Traits1> y;
    SomeClass<Traits2> z;

    x.useTraits();
    y.useTraits();
    z.useTraits();

    return 0;
}

// output:
// standard
// traits1
// traits2

另请参阅:https://en.wikipedia.org/wiki/Policy-based_design