如果模板實體化時型別是完整的,那么在模板中使用不完整的型別是否合法?
如下
#include <iostream>
struct bar;
template <typename T>
struct foo {
foo(bar* b) : b(b) {
}
void frobnicate() {
b->frobnicate();
}
T val_;
bar* b;
};
struct bar {
void frobnicate() {
std::cout << "foo\n";
}
};
int main() {
bar b;
foo<int> f(&b);
f.frobnicate();
return 0;
}
Visual Studio 編譯上面沒有抱怨。GCC 發出警告invalid use of incomplete type 'struct bar'但編譯。Clang 出錯了member access into incomplete type 'bar'。
uj5u.com熱心網友回復:
代碼格式錯誤,不需要診斷。
[temp.res.general]/6.4可以在任何實體化之前檢查模板的有效性。
程式格式錯誤,無需診斷,如果:
...
— 緊接其定義的模板的假設實體化將由于不依賴于模板引數的構造而格式錯誤,...
如果您絕對不能bar在模板之前定義,則有一個解決方法:您可以在模板引數上引入人為依賴。
template <typename T, typename, typename...>
struct dependent_type {using type = T;};
template <typename T, typename P0, typename ...P>
using dependent_type_t = typename dependent_type<T, P0, P...>::type;
然后使用dependent_type_t<bar, T>代替bar。
uj5u.com熱心網友回復:
盡管 MSVC 和 GCC 的行為也符合標準,但 Clang 報告錯誤(而不是警告或對此保持沉默)是正確的。有關詳細資訊,請參閱@HolyBlackCat 的回答。
您發布的代碼是格式錯誤的 NDR。但是,您要做的事情是可行的。
您可以像處理非模板類一樣推遲模板成員函式的定義。就像非模板類一樣,只要這些需要bar是完整型別的定義只發生一次bar,就可以了。
唯一的小問題是您需要將方法顯式標記為行內以避免在多 TU 程式中違反 ODR,因為定義幾乎肯定會在標題中。
#include <iostream>
struct bar;
template <typename T>
struct foo {
foo(bar* b) : b(b) {
}
inline void frobnicate();
T val_;
bar* b;
};
struct bar {
void frobnicate() {
std::cout << "foo\n";
}
};
template <typename T>
void foo<T>::frobnicate() {
b->frobnicate();
}
int main() {
bar b;
foo<int> f(&b);
f.frobnicate();
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/337399.html
