![](/img/trans.png)
[英]Template specialisation with enable_if and is_arithmetic for a class
[英]Troubles with std::enable_if and std::is_arithmetic as template parameter
我正在嘗試實現一個OutputArchive
模板類,它具有模板化函數processImpl()
。 看起來像這樣:
template<typename ArchiveType>
class OutputArchive {
...
template<typename Type, typename std::enable_if_t<std::is_arithmetic_v<Type>>> inline
ArchiveType& processImpl(Type&& type) {
// Implementation
}
template<typename Type, typename = void> inline
ArchiveType& processImpl(Type&& type) {
// Implementation
}
}
這里的想法是,如果我將一個char
, int
, float
等傳遞給我的processImpl()
函數,應該使用第一個重載; 然而,事實並非如此。 第二次重載似乎總是被使用,我完全不知道我可能做錯了什么。 我想它確實與我使用std::enable_if
所以要使它工作,你應該使用std :: enable_if 2個案例。 我將展示返回類型的示例,但使用模板參數也可以。
template<typename Type> inline
typename std::enable_if_t<std::is_arithmetic_v<Type>, ArchiveType&> processImpl(Type&& type) {
// Implementation
}
template<typename Type> inline
typename std::enable_if_t<!std::is_arithmetic_v<Type>, ArchiveType&> processImpl(Type&& type) {
// Implementation
}
請注意第二種情況中的否定。
但是從C ++ 17開始,更好的方法是使用constexpr:
ArchiveType& processImpl(Type&& type) {
if constexpr(std::is_arithmetic_v<type>) {
// implementation
} else {
// implementation
}
}
您的代碼中存在一些問題。
沒有特別的順序
1)不是錯誤(我猜)但是......使用typename std::enable_if<...>::type
或者從C ++ 14開始, std::enable_if_t<...>
; 在std::enable_if_t
之前不需要使用typename
2)如果你想在參數類型列表中使用std::enable_if
,這個不起作用
template <typename T, std::enable_if_t<(test with T)>>
因為,如果用T
測試是真的,就變成了
template <typename T, void>
作為模板函數的簽名沒有意義。
您可以SFINAE啟用/禁用返回值(請參閱Igor或Marek R的答案)或者您可以編寫,而不是
template <typename T, std::enable_if_t<(test with T)> * = nullptr>
成為
template <typename T, void * = nullptr>
並且有意義,作為簽名,並且有效
3)如注釋中所指出的,你應該使用std::remove_reference
,所以
template <typename Type,
std::enable_if_t<std::is_arithmetic_v<
std::remove_reference_t<Type>>> * = nullptr> inline
ArchiveType & processImpl (Type && type)
現在這個函數應該攔截算術值,但......
4)前面的processImpl()
,對於算術值,與其他processImpl()
沖突,因為在算術值的情況下,兩個版本都匹配,編譯器不能選擇另一個。
我可以建議兩種解決方案
(a)通過SFINAE禁用算術案例中的第二個版本; 我的意思是,寫下第二個如下
template <typename Type,
std::enable_if_t<false == std::is_arithmetic_v<
std::remove_reference_t<Type>>> * = nullptr> inline
ArchiveType & processImpl (Type && type)
(b)中通過該發送的附加的中間函數int
值和接收int
在算術版本和一個long
的通用的; 我的意思是
template <typename Type,
std::enable_if_t<std::is_arithmetic_v<
std::remove_reference_t<Type>>> * = nullptr> inline
ArchiveType & processImpl (Type && type, int)
{ /* ... */ }
template <typename Type>
ArchiveType & processImpl (Type && type, long)
{ /* ... */ }
template <typename Type>
ArchiveType & processImpl (Type && type)
{ return processImpl(type, 0); }
這樣,算法版本(完全接收int
)優先於通用版本(在啟用時); 否則使用通用版本。
以下是基於(b)解決方案的完整工作C ++ 14示例
#include <iostream>
#include <type_traits>
template <typename ArchiveType>
struct OutputArchive
{
ArchiveType value {};
template <typename Type,
std::enable_if_t<std::is_arithmetic_v<
std::remove_reference_t<Type>>> * = nullptr> inline
ArchiveType & processImpl (Type && type, int)
{
std::cout << "--- processImpl aritmetic: " << type << std::endl;
return value;
}
template <typename Type>
ArchiveType & processImpl (Type && type, long)
{
std::cout << "--- processImpl generic: " << type << std::endl;
return value;
}
template <typename Type>
ArchiveType & processImpl (Type && type)
{ return processImpl(type, 0); }
};
int main()
{
OutputArchive<int> oa;
long l{2l};
oa.processImpl(l);
oa.processImpl(3);
oa.processImpl("abc");
}
這應該可以解決問題
template<typename ArchiveType>
class OutputArchive {
...
template<typename Type>
inline
typename std::enable_if_t<std::is_arithmetic_v<Type>, ArchiveType&>
processImpl(Type type) {
// Implementation
}
template<typename Type>
inline
typename std::enable_if_t<!std::is_arithmetic_v<Type>, ArchiveType&>
processImpl(Type&& type) {
// Implementation
}
};
現場樣本 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.