簡體   English   中英

enable_if和多個條件的問題

[英]Issue with enable_if and multiple conditions

我試圖實現一個將泛型類型轉換為字符串的函數。 積分類型需要使用std::to_string() ,字符串和字符使用std::string()和逐個元素的元素轉換為使用其他方法之一的字符串(取決於它們的內容)。

這就是我所擁有的:

//Arithmetic types    

template<class T>
typename std::enable_if<std::is_arithmetic<T>::value, std::string>::type convertToString(const T& t){
    return std::to_string(t);
}

//Other types using string ctor

template<class T>
typename std::enable_if<std::__and_<std::__not_<std::is_arithmetic<T>>::type,
        std::__not_<std::is_same<T, <T,
       std::vector<typename T::value_type, typename T::allocator_type>>::value
       >>>::value, std::string>::type convertToString(const T& t){
    return std::string(t);
}

//Vectors

template<class T>
typename std::enable_if<std::is_same<T, std::vector<typename T::value_type, 
   typename T::allocator_type>>::value, std::string>::type convertToString(const T& t){
    std::string str;
    for(std::size_t i = 0; i < t.size(); i++){
        str += convertToString(t[i]);
    }
    return str;
}

問題是第二個函數沒有編譯。 如何設計第二個函數以便它編譯(和工作)並且不會產生歧義問題?

Oktalist的答案解釋了為什么你的類型特征不能編譯。 此外,您不應該使用__and___not_ 這些是保留的,可以在下一個編譯器版本中輕松更改。 實現這些特征的自己版本很容易(例如,參見可能的conjunction實現)。

我建議采用完全不同的方法。 我們可以使用choice<>來使這些情況重載更簡單:

template <int I> struct choice : choice<I+1> { };
template <> struct choice<10> { };

通過:

// arithmetic version
template <class T>
auto convertToStringHelper(T const& t, choice<0> )
    -> decltype(std::to_string(t))
{
    return std::to_string(t);
}

// non-arithmetic version
template <class T>
auto convertToStringHelper(T const& t, choice<1> )
    -> decltype(std::string(t))
{
    return std::string(t);
}

// vector version
template <class T, class A>
std::string convertToStringHelper(std::vector<T,A> const& v, choice<2> )
{
    // implementation here
}

template <class T>
std::string convertToString(T const& t) {
    return convertToStringHelper(t, choice<0>{});
}

這很好,因為你得到的所有SFINAE都沒有任何enable_if cruft。

一種可能的方法是添加is_vector trait( 在此處查看更多詳細信息):

template<typename T> struct is_vector : public std::false_type {};

template<typename T, typename A>
struct is_vector<std::vector<T, A>> : public std::true_type {};

然后修改convertToString函數模板,如下所示:

// Arithmetic types

template<class T>
typename std::enable_if<std::is_arithmetic<T>::value, std::string>::type convertToString(const T& t) {
    return std::to_string(t);
}

// Other types using string ctor

template<class T>
typename std::enable_if<!std::is_arithmetic<T>::value && !is_vector<T>::value, std::string>::type convertToString(const T& t) {
    return std::string(t);
}

// Vectors

template<class T>
typename std::enable_if<!std::is_arithmetic<T>::value && is_vector<T>::value, std::string>::type convertToString(const T& t) {
    std::string str;
    for(std::size_t i = 0; i < t.size(); i++){
        str += convertToString(t[i]);
    }
    return str;
}

wandbox示例

標記錯誤的模板:

template<class T>
typename std::enable_if<std::__and_<std::__not_<std::is_arithmetic<T>>::type,
//                                                                    ^^^^^^[1]
        std::__not_<std::is_same<T, <T,
//                                  ^^^[2]
       std::vector<typename T::value_type, typename T::allocator_type>>::value
//                                                                     ^^^^^^^[3]
       >>>::value, std::string>::type convertToString(const T& t){
//       ^[4]
    return std::string(t);
}
// [1] nested ::type not needed and ill-formed without typename keyword
// [2] <T, is garbage
// [3] nested ::value ill-formed because std::__not_ argument must be a type
// [4] too many closing angle brackets

修復了錯誤的模板:

template<class T>
typename std::enable_if<std::__and_<std::__not_<std::is_arithmetic<T>>,
        std::__not_<std::is_same<T,
       std::vector<typename T::value_type, typename T::allocator_type>>
       >>::value, std::string>::type convertToString(const T& t){
    return std::string(t);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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