没有显式特化声明的显式模板特化
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>::foo
和 FooNoDef<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);
我有小示例代码:
文件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>::foo
和 FooNoDef<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);