![](/img/trans.png)
[英]How to deduce template return type with another template parameter with explicit specialization?
[英]Template specialization and explicit specification of return type vs. auto
考慮一下代碼:
class Test {
public:
template<int N> auto foo() {}
template<> auto foo<0>() { return 7; }
template<int N> void bar() {}
template<> int bar<0>() { return 7; }
};
我已經使用不同的編譯器(通過Compiler Explorer )測試了代碼。
如果使用Clang 7.0.0 ,則foo
編譯,而bar
給出錯誤:
:8:20:錯誤:沒有功能模板與功能模板專業化“酒吧”匹配
template<> int bar<0>() { return 7; } ^
:7:26:注意:候選模板被忽略:無法將'void()'與'int()'相匹配
template<int N> void bar() {}; ^
Visual C ++同意(MSVC 19 2017 RTW):
(8):錯誤C2912:顯式專門化'int Test :: bar(void)'不是功能模板的專門化
gcc 8.2不會編譯任何代碼(盡管原因可能是C ++ 17支持中的錯誤 :
:5:14:錯誤:非命名空間范圍“類測試”中的顯式專業化
template<> auto foo<0>() { return 7; }; ^
:5:28:錯誤:主模板的聲明中的template-id'foo <0>'
template<> auto foo<0>() { return 7; }; ^
:7:26:錯誤:模板參數列表過多
template<int N> void bar() {}; ^~~
:8:14:錯誤:非命名空間范圍“類測試”中的顯式專業化
template<> int bar<0>() { return 7; } ^
:8:20:錯誤:預期為';' 在成員聲明結束時
template<> int bar<0>() { return 7; } ^~~ ;
:8:23:錯誤:“ <”令牌之前的預期unqualified-id
template<> int bar<0>() { return 7; } ^
這里的正確解釋是什么? 我可以針對不同的方法專長使用不同的返回類型嗎(為什么只使用auto
,而沒有在明確指定它們時指定)? 由於對auto
和template的了解有限,我會說“ no”。 我不明白為什么要使用auto
而不是顯式命名返回類型來允許針對不同的專業使用不同的返回類型。
但是,這些代碼是我在其他地方找到的代碼的簡化版本,所以也許我的解釋不正確-在那種情況下,我將不勝感激地解釋為什么將auto
用於專業化時為什么允許使用不同的返回類型,同時明確命名該類型似乎是被禁止的 。
示例代碼有幾個不同的問題。
1)GCC無法實現CWG 727(在C ++ 17中是必需的): https ://gcc.gnu.org/bugzilla/show_bug.cgi?id=85282會導致error: explicit specialization in non-namespace scope 'class Test'
2)如果我們忽略這一點,示例代碼可以簡化為
template<int N> auto foo() {}
template<> auto foo<0>() { return 7; }
template<int N> void bar() {}
template<> int bar<0>() { return 7; }
仍然顯示相同的錯誤。 現在,所有編譯器都同意輸出。 他們編譯foo
s並在專業bar
上出錯。
為什么使用auto進行專業化時為何允許不同的返回類型
如果專業化也具有auto
占位符,則標准允許使用auto
返回類型的專業化功能
具有使用占位符類型的已聲明返回類型的函數或函數模板的重新聲明或特化也應使用該占位符,而不是推導類型
http://eel.is/c++draft/dcl.spec.auto#11
因此,憑借符合標准的專業化(類似於給定的示例之一),並且在任何允許的地方都沒有明確禁止。
至於bar
的錯誤,標准說返回類型是函數模板簽名的一部分:
“功能模板”的名稱,參數類型列表([dcl.fct]),封閉的名稱空間(如果有的話), 返回類型 ,模板頭和尾隨的要求子句([dcl.decl])(如果有的話)
http://eel.is/c++draft/defns.signature.templ
因此,在編譯器看來, template<> int bar<0>() { return 7; }
template<> int bar<0>() { return 7; }
是template<... N> int bar();
的特殊化template<... N> int bar();
模板(注意返回類型)。 但是以前沒有聲明過(專業化不能在聲明之前),所以編譯失敗! 如果添加template<int N> int bar();
然后它將進行編譯(但是如果您嘗試調用bar
則會抱怨調用不明確)。
基本上,您不能以特殊化方式更改函數簽名,只能對(duh)模板參數進行特殊化處理(模板參數也應與聲明中的參數完全相同,因為它也是簽名的一部分)。
我是否可以擁有一個模板專門化,其顯式聲明的返回類型與基本模板完全不同
如前所述-您無法更改函數模板簽名,這意味着您無法更改返回類型。 但是,如果返回類型取決於模板參數,則可以對其進行專門化處理!
考慮
template<int N, typename R = void> R bar() {}
template<> int bar<0>() { return 7; }
// bar<0, int> is deduced, see: http://eel.is/c++draft/temp.expl.spec#10
這是允許的,但是它有一個缺點,當您要調用特殊化時必須寫bar<0, int>
: https : //godbolt.org/z/4lrL62
可以通過在原始聲明中將條件類型設置為條件來解決此問題: https : //godbolt.org/z/i2aQ5Z
但是一旦專業化的數量增加,要維護它很快就會變得很麻煩。
另一個也許更可維護的選項是返回類似ret_type<N>::type
東西,並將其與bar
一起專門化。 但是它仍然不會像使用auto
那樣干凈。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.