如果存在,如何调用派生中的函数,否则如果使用 CRTP,则使用默认值?

Pal*_*han 0 c++ templates crtp template-meta-programming

我有一个针对某些结构的辅助基类,它使用 CRTP 来帮助我获取有关它们的一些信息:

template <class T>
struct MyHelper
{
    size_t size() const { return sizeof(T); }
};
Run Code Online (Sandbox Code Playgroud)

我已经在代码库的各个库中使用了使用此定义的结构,并且我希望有一种方法来记录它们。我的第一个想法是这样的:

template <class T>
struct MyHelper
{
    size_t size() const { return sizeof(T); }
    virtual void print(std::ostream& out) const { out << "(" << sizeof(T) << ")"; }
};
Run Code Online (Sandbox Code Playgroud)

但后来我意识到这行不通,原因有几个 - 其中之一是添加虚拟实际上改变了 POD 数据的大小。

有没有办法在没有 virtual 关键字的情况下让我拥有一个使用上述实现的默认 toStr 方法,除非特定的派生类 T 有一个实现,在这种情况下它会遵循该实现?

Win*_*ute 5

我认为做这样的事情最直接的方法是分派到一个不同的非虚拟函数,派生类可以根据需要隐藏该函数。例如:

template <class T>
struct MyHelper
{
  size_t size() const { return sizeof(T); }

  void print(std::ostream &out) const {
    // Cast to derived, call do_print. This will be derived's do_print
    // if it exists and MyHelper's otherwise.
    static_cast<T const*>(this)->do_print(out);
  }

  void do_print(std::ostream& out) const {
    out << "(" << sizeof(T) << ")";
  }
};


struct A : MyHelper<A> {
  // no do_print, so MyHelper<A>'s will be used
  int x;
};

struct B : MyHelper<B> {
  // B's do_print is found and used in MyHelper<B>::print
  void do_print(std::ostream &out) const {
    out << "Hello!\n";
  }
};

template<typename T>
void foo(MyHelper<T> const &r) {
  r.print(std::cout);
}

int main() {
  A a;
  B b;

  foo(a);
  foo(b);
}
Run Code Online (Sandbox Code Playgroud)

输出:

(4)Hello!
Run Code Online (Sandbox Code Playgroud)

您也可以使用 SFINAE 构建不需要第二个成员函数的东西,但我怀疑增加的复杂性是否值得。