簡體   English   中英

使用std :: enable_if和std :: is_arithmetic作為模板參數進行故障

[英]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
    }
}

這里的想法是,如果我將一個charintfloat等傳遞給我的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM