CRTP 派生的模板化方法调用在“>”标记之前产生预期的主表达式

CRTP derived templated method call yields expected primary-expression before ‘>’ token

以下示例未编译并出现错误 error: expected primary-expression before ‘>’ token。我不懂为什么。我正在尝试调用派生的 CRTP 模板化方法。我用 CRTP 这样做是因为你不能有 virtual 模板化方法。

https://godbolt.org/z/PMfsPM

#include <iostream>
#include <memory>
#include <type_traits>

struct Foo
{
  Foo(int xx, int yy) : x(xx), y(yy) {}
  int x, y;
};
struct Bar
{
  Bar(int xx, int yy, int zz) : x(xx), y(yy), z(zz) {}
  int x, y, z;
};

template<class Derived = void>
class Base
{
public:
  template<class T>
  std::unique_ptr<T> makeTImpl(int x, int y) {
    return std::make_unique<T>(x, y);
  }
  template<class T>
  std::unique_ptr<T> makeT(int x, int y)
  {
    if constexpr (std::is_same_v<Derived, void>) {
      return makeTImpl<T>(x, y);
    } else {
      auto& d = *static_cast<Derived*>(this);
      return d.makeTImpl<T>(x, y); // error: expected primary-expression before ‘>’ token
    }
  }
};

class Derived : public Base<Derived>
{
public:
  Derived(int z) : _z(z) {}

  template<class T>
  std::unique_ptr<T> makeTImpl(int x, int y) {
    return std::make_unique<T>(x, y, _z);
  }
private:
  int _z;
};

int main() {
  Base b;
  b.makeT<Foo>(1, 2);
  Derived d(3);
  d.makeT<Bar>(1, 2);
}

makeTImpl 是函数模板,在依赖上下文中使用。所以代替:

d.makeTImpl<T>(x, y);

你需要写:

d.template makeTImpl<T>(x, y);
//^^^^^^^^

这是 demo

请参阅此 post 以了解有关哪些上下文需要 template 关键字的详细信息。