没有显式特化声明的显式模板特化

explicit template specialization with no explicit specialization declaration

我有小示例代码:

文件foo.h:

#pragma once

template <typename T> class FooNoDef {
public:
  void foo(const T& value); // declared and not defined
};

class FooUser {
public:
  template <typename T> static void useFoo(const T& value) {
    FooNoDef<T>{}.foo(value);
  }
};

文件xy.h:

#pragma once

struct X {};
struct Y {};

文件xy.cpp:

#include "foo.h"
#include "xy.h"
#include <iostream>

template <> void FooNoDef<X>::foo(const X& value) {
  std::cout << "x" << std::endl;
}

template <> void FooNoDef<Y>::foo(const Y& value) {
  std::cout << "y" << std::endl;
}

最后 main.cpp:

#include "foo.h"
#include "xy.h"

int main() {
  FooUser::useFoo(X{});
  FooUser::useFoo(Y{});
  return 0;
}

此代码使用 gcc 11 和 clang 13 编译。我怀疑我的代码格式错误,但我无法通过阅读标准找到明确的答案:

第 13.9.4 节 [temp.expl.spec](强调我的):

If a template, a member template or a member of a class template is explicitly specialized, a declaration of that specialization shall be reachable from every use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit specialization that is declared but not defined.

第 13.9.2 节 [temp.inst](强调我的):

[Example 5:

template<class T> struct Z {
  void f();
  void g();
};

void h() {
  Z<int> a;         // instantiation of class Z<int> required
  Z<char>* p;       // instantiation of class Z<char> not required
  Z<double>* q;     // instantiation of class Z<double> not required

  a.f();            // instantiation of Z<int>​::​f() required
  p->g();           // instantiation of class Z<char> required, and
                    // instantiation of Z<char>​::​g() required
}

Nothing in this example requires class Z, Z​::​g(), or Z​::​f() to be implicitly instantiated.** — end example]

我认为 FooUser::useFoo() 不会像讨论的标准中的示例那样导致 FooNoDef::foo() 的隐式实例化,但我仍然没有为 FooNoDef<X> 和 [ 的显式特化提供声明=18=]。我的示例违反了哪条 C++ 规则(如果有的话)?我是否必须严格在 FooUser::useFoo() 的主体之前提供明确的专业化声明 template <> void FooNoDef<X>;template <> void FooNoDef<Y>;

据我所知,你是对的,虽然你把重点放在了标准的错误行上:

[...] a declaration of that specialization shall be reachable from every use of that specialization [...]

main中,FooUser::useFoo<X>FooUser::useFoo<Y>都需要实例化。这些然后需要实例化 FooNoDef<X>::fooFooNoDef<Y>::foo – 这里会导致隐式实例化,如果 没有显式实例化可用。

然而,在 xy.cpp 中只存在一个定义,main.cpp 看不到它,并且没有可见的声明 – 违反了上面引用的短语,因此你的程序确实是 ill-formed.

要修复,您需要添加声明,例如在 xy.h 中(注意:header 包含在 main.cpp 中):

template <> void FooNoDef<X>::foo(X const& value);
template <> void FooNoDef<Y>::foo(Y const& value);