[英]Clang does not notice default template parameters
根據C ++標准,當使用默認模板參數向前聲明模板類型時,它們中的每一個都只能出現在一個聲明中。 例如:
// GOOD example
template <class T = void>
class Example; // forward-declaration
template <class T>
class Example {}; // definition
// GOOD example
template <class T>
class Example; // forward-declaration
template <class T = void>
class Example {}; // definition
// BAD example
template <class T = void>
class Example; // forward-declaration
template <class T = void> // ERROR: template parameter redefines default argument
class Example {}; // definition
在我的代碼中,我在不同的文件中有很多前向聲明,所以將默認參數放在定義中是有意義的:
// foo.hpp, bar.hpp, baz.hpp, etc.
template <class T>
class Example;
// example.hpp
template <class T = void>
class Example {};
而且,正如所料,它在所有地方都運作良好......除了鏗鏘! 我將問題縮小到這個范圍:
在clang中,如果類模板具有默認參數,但它們未在該類的第一個前向聲明中聲明 ,並且在聲明該類的實例時未指定尖括號 ,則clang忽略默認參數並引發錯誤“否”可行的構造函數或演繹指南,用於推導......的模板參數。“
// GOOD example
template <class T>
class Example;
template <class T = void>
class Example {};
int main() {
Example e; // error: no viable constructor or deduction guide for deduction of template arguments of 'Example'
}
= void
to forward聲明修復了這個問題,但對我來說不可行,因為我的forward-decl在不同的文件中,我不知道哪一個會先出現。 (也是超級問題,因為我的默認值將在代碼庫深處的某個模糊文件中) Example e;
Example<> e;
修復了這個問題,但對我來說不可行,因為我是一個庫開發人員,並且不希望我的所有用戶在我的課程后輸入<>
。 example_fwd.hpp
,其中包含一個前向聲明並包含它,而不是每次都向前聲明修復問題,但如果有更好的解決方案,我想避免這種情況。 在這種情況下誰是對的:clang或其他編譯器? 這是編譯器錯誤嗎? 我怎樣才能繞過這個問題(除了我上面描述的部分解決方案)? 我找到了#10147 (和相關的stackoverflow問題),但它是關於模板模板參數,並且在一年前也被標記為已修復。
這看起來像一個bug,現在報告在LLVM bugtracker ( #40488 )上。
我不知道誰是對的,但......
我怎樣才能繞過這個問題(除了我上面描述的部分解決方案)?
添加以下扣除規則怎么樣?
Example() -> Example<>;
以下代碼使用g ++和clang ++編譯(顯然是C ++ 17)
template <class T>
class Example;
template <class T = void>
class Example {};
Example() -> Example<>;
int main() {
Example e;
}
考慮以下因素:
[temp.param] / 12 - 可以使用的默認模板參數集是通過合並模板的所有先前聲明中的默認參數獲得的,其方式與默認函數參數相同[ 示例 :
template<class T1, class T2 = int> class A; template<class T1 = int, class T2> class A;
相當於
template<class T1 = int, class T2 = int> class A;
- 結束例子 ]
可用的默認參數
template <class T>
class Example;
template <class T = void>
class Example {};
將是Example
定義中的默認參數。 上面的兩個聲明將相當於具有單個聲明
template <class T = void>
class Example {};
這將有效地允許做Example e
。
應接受原始代碼。 作為一種解決方法,已在max66的答案中提出 ,您可以提供使用默認參數的演繹指南
Example() -> Example<>;
該標准不區分定義中是否定義了默認模板參數或模板的聲明。
因為Clang在聲明中出現默認參數時接受代碼,但在定義中沒有,所以這兩種行為中至少有一種是錯誤的。 考慮[over.match.class.deduct] /1.1.1:
模板參數是C的模板參數,后跟構造函數的模板參數(包括默認模板參數),如果有的話。
,我很想說Clang應該使用默認的模板參數。
我認為您可以通過遵循常規做法來避免此錯誤:
如果必須轉發聲明,請為此前向聲明創建專用頭文件。
在此前向聲明文件中定義默認參數
還要在頭文件中包含此文件,該文件提供模板的定義。
作為示例,請參閱iosfwd
: libstdc ++ / iosfwd
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.