没有显式专业化声明的显式模板专业化
我有一个小示例代码:
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()
的隐式实例化,如所讨论的标准中的示例,但我仍然从未为我的显式专业化提供声明的FooNoDef
和 FooNoDef
。我的示例违反了 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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
据我所知,您是对的,尽管您强调了标准的错误行:
在
main
内,FooUser::useFoo
和FooUser::useFoo
需要实例化。然后需要实例化FooNoDef::foo
和FooNoDef::foo
- 这里会导致隐式实例化,if 没有可用的显式实例化。但是,仅在
xy.cpp
中存在定义,并且对main.cpp
不可见,并且没有可见的声明 - 违反了上面引用的短语,因此您的程序确实格式不正确。要修复此问题,您需要添加一个声明,例如在
xy.h
中(注意:main.cpp
包含的标头):As far as I can see, you are right, though you've put emphasise on the wrong line of the standard:
Within
main
, both ofFooUser::useFoo<X>
andFooUser::useFoo<Y>
need to be instantiated. These then need to instantiateFooNoDef<X>::foo
andFooNoDef<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 tomain.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 bymain.cpp
):