我有小示例代碼:
檔案 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;
}
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()?
uj5u.com熱心網友回復:
據我所知,您是對的,盡管您強調了標準的錯誤行:
[...] 每次使用該專業時都應能獲得該專業的宣告 [...]
在main中,FooUser::useFoo<X>和都FooUser::useFoo<Y>需要實體化。然后這些需要實體化FooNoDef<X>::foo,并且-如果沒有顯式實體化可用FooNoDef<Y>::foo,這里將導致隱式實體化。
但是,在 中只存在一個定義xy.cpp,并且對 是不可見的main.cpp,并且沒有可見的宣告——違反了上面參考的短語,因此您的程式確實是格式錯誤的。
要修復,您需要添加一個宣告,例如在xy.h(注意:包含在的標頭main.cpp)中:
template <> void FooNoDef<X>::foo(X const& value);
template <> void FooNoDef<Y>::foo(Y const& value);
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/448839.html
標籤:c c 11 templates language-lawyer
