没有显式专业化声明的显式模板专业化

发布于 2025-01-16 12:16:33 字数 2570 浏览 1 评论 0原文

我有一个小示例代码:

file 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);
  }
};

file xy.h:

#pragma once

struct X {};
struct Y {};

file 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](强调我的):

如果模板、成员模板或类模板的成员是 明确专业化,该专业化的声明应 每次使用该专业化都会导致 隐式实例化发生在每个翻译单元中 发生这种使用的情况;无需诊断。如果程序 没有提供显式专业化的定义,并且 要么专业化的使用方式会导致 隐式实例化发生或者成员是虚拟成员 函数,程序格式错误,无需诊断。一个 永远不会为显式实例化生成隐式实例化 已声明但未定义的专业化。

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

[示例 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
}

此示例中没有任何内容需要类 Z、Z :: g() 或 Z :: f() 隐式实例化。** — 结束示例]

我认为 < code>FooUser::useFoo() 不会导致 FooNoDef::foo() 的隐式实例化,如所讨论的标准中的示例,但我仍然从未为我的显式专业化提供声明的FooNoDefFooNoDef。我的示例违反了 C++ 的哪条规则(如果有)?我是否必须提供显式的专业化声明 template <> void FooNoDef;template <> void FooNoDef; 严格位于 FooUser::useFoo() 主体之前?

I have small example code:

file 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);
  }
};

file xy.h:

#pragma once

struct X {};
struct Y {};

file 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;
}

and finally main.cpp:

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

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

This code compiles with gcc 11 and clang 13. I suspect my code is ill-formed, but I can't find a definite answer from reading the standard:

Section 13.9.4 [temp.expl.spec] (emphasis mine):

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.

Section 13.9.2 [temp.inst] (emphasis mine):

[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]

I think FooUser::useFoo() does not cause implicit instantiation of FooNoDef::foo() as the example from the standard discussed, but still I never provided a declaration for my explicit specialization of FooNoDef<X> and FooNoDef<Y>. Which rule of C++, if any, do I violate with my example? Would I have to provide explicit specialization declaration template <> void FooNoDef<X>; and template <> void FooNoDef<Y>; strictly before the body of FooUser::useFoo()?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

旧城空念 2025-01-23 12:16:33

据我所知,您是对的,尽管您强调了标准的错误行:

[...]该专业化的声明应可从该专业化的每次使用中获得[...]

main 内,FooUser::useFooFooUser::useFoo 需要实例化。然后需要实例化 FooNoDef::fooFooNoDef::foo - 这里会导致隐式实例化,if 没有可用的显式实例化。

但是,仅在 xy.cpp 中存在定义,并且对 main.cpp 不可见,并且没有可见的声明 - 违反了上面引用的短语,因此您的程序确实格式不正确。

要修复此问题,您需要添加一个声明,例如在 xy.h 中(注意:main.cpp 包含的标头):

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

As far as I can see, you are right, though you've put emphasise on the wrong line of the standard:

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

Within main, both of FooUser::useFoo<X> and FooUser::useFoo<Y> need to be instantiated. These then need to instantiate FooNoDef<X>::foo and FooNoDef<Y>::foo – and here an implicit instantiation would be caused, if no explicit instantiation was available.

However, there only exists a definition within xy.cpp, and that's not visible to main.cpp, and there's no visible declaration – violating above cited phrase, thus your programme indeed is ill-formed.

To fix, you'd need to add a declaration, e.g. in xy.h (note: the header that is included by main.cpp):

template <> void FooNoDef<X>::foo(X const& value);
template <> void FooNoDef<Y>::foo(Y const& value);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文