-1

看一下以下简单的奇怪重复模板模式 (CRTP) 示例:

template<class Derived>
struct base
{
    void foo() {
        static_cast<Derived*>(this)->foo();
    }
};

struct derived
    : public base<derived>
{};

由于除了派生自的derived成员函数之外没有其他成员函数,因此调用会产生无限递归。我们可以修改这样的定义,只在有 a 时调用?foobasederived{}.foo()base::foostatic_cast<Derived*>(this)->foo()Derived::foo

编辑:我问的原因是foo在我的实际应用程序中有一个模板参数。而且由于模板方法不能是虚拟的,CRTP 似乎是唯一的解决方法。

4

2 回答 2

1

我们可以修改这样的定义,base::foostatic_cast<Derived*>(this)->foo()在有 a 时调用Derived::foo

强制定义的一种方法Derived::foo是使用虚拟参数重载函数。

template <typename Derived>
struct base
{
    void foo() {
        static_cast<Derived*>(this)->foo(0);   // Requires Derived::foo(int)
    }
};

或者

template <typename Derived>
struct base
{
    void foo(int ) {
        static_cast<Derived*>(this)->foo();  // Requires Derived::foo(void)
    }
};
于 2020-04-01T17:49:45.183 回答
0

如果您愿意将返回类型更改base::foo为虚拟标签,我们可以检查调用是否Derived::foo返回相同的标签,并取决于该调用的派生版本。

#include <iostream>

template<class Derived>
class base
{
    private:
    struct Tag {};

    public:
    Tag foo() {
        if constexpr (!std::is_same_v<decltype(std::declval<Derived>().foo()), Tag>) {
            static_cast<Derived*>(this)->foo();
        }

        return {};
    }
};

struct derived
    : public base<derived>
{};

struct derived2
    : public base<derived>
{
    void foo() { std::cout << "foo!"; }
};

int main() {
    derived d;
    derived2 d2;

    d.foo();
    d2.foo();
}
于 2020-04-01T18:05:53.763 回答