没有前向声明,模板专业化无法解析 this-context 方法

Template specialisation unable to resolve this-context method without forward-declaration

我有一个模板 class,它大致采用下面给定代码的形式。

template <int index = 0>
struct Thing {
  void Hello();
  void Greet(const char *name);
};

这对于它的目的来说工作得很好,直到你决定尝试在它自己身上调用方法。假设您定义如下所示的方法。

template <>
void Thing<>::Greet(const char *name) {
  Hello();
  printf(", %s!\n", name);
}

template <>
void Thing<>::Hello() {
  printf("Hello");
}

然后调用 Greet() 会产生一个明确的特化错误,我觉得这很奇怪。编译器应该通过其接口声明知道 this 的所有方法,但出于某种原因,它无法在这种情况下解析它。这可以通过以下两种方式之一解决;您必须转发声明对您自己调用的任何方法,或者确保这些方法的定义顺序确保您调用的方法已预先定义。

这个问题真的很烦人,因为我提供了接口声明,模板的任何特化都应该符合相同的接口,所以我真的不明白为什么编译器会抱怨这个——有没有解决问题的方法,而不用每个方法的前向声明污染代码,或者必须以特定方式对方法进行排序?

希望您有一些好的想法来更好地解决问题。提前致谢!

为了便于重现问题,这里有一个片段将调用有问题的方法。

int main(int argc, const char *argv[]) {
  Thing<0> thing_with_zero;
  thing_with_zero.Greet("World");
  return 0;
}

您可以对整个 class 进行专业化以确保看到专业化:

// Primary template
// generic one
template <int index = 0>
struct Thing {
    void Hello() {/*..*/}
    void Greet(const char *name) {/*..*/}
};

// Specialization for index == 0
template <>
struct Thing<0> {
    void Greet(const char *name) {
        Hello();
        printf(", %s!\n", name);
    }
    void Hello() {
        printf("Hello");
    }
};

或者,您可以在 if constexpr (C++17) 的帮助下放弃专业化:

template <int index = 0>
struct Thing
{
    void Greet(const char *name) {
        if constexpr (index == 0) {
            Hello();
            printf(", %s!\n", name);
        } else {
            // ...
        }
    }
    void Hello() {
        if constexpr (index == 0) {
            printf("Hello");
        } else {
            // ...
        }
    }
};