简体   繁体   English

enable_if和多个条件的问题

[英]Issue with enable_if and multiple conditions

I tried to implement a function which converts a generic type to a string. 我试图实现一个将泛型类型转换为字符串的函数。 Integral types need to be converted using std::to_string() , strings and chars using std::string() and vectors, element by element, to a string using one of the other methods (depending on their content). 积分类型需要使用std::to_string() ,字符串和字符使用std::string()和逐个元素的元素转换为使用其他方法之一的字符串(取决于它们的内容)。

This is what I have: 这就是我所拥有的:

//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;
}

The problem is that the 2nd function does not compile. 问题是第二个函数没有编译。 How can I design the 2nd function so that it does compile (and work) and does not create ambiguity issues? 如何设计第二个函数以便它编译(和工作)并且不会产生歧义问题?

Oktalist's answer explains why your type trait doesn't compile. Oktalist的答案解释了为什么你的类型特征不能编译。 Also, you shouldn't use __and_ and __not_ . 此外,您不应该使用__and___not_ Those are reserved and could easily change in the next compiler version. 这些是保留的,可以在下一个编译器版本中轻松更改。 It's easy enough to implement your own version of those traits (eg see the possible implementation of conjunction ). 实现这些特征的自己版本很容易(例如,参见可能的conjunction实现)。

I would suggest an entirely different approach. 我建议采用完全不同的方法。 We can use choice<> to make overloading these cases far simpler: 我们可以使用choice<>来使这些情况重载更简单:

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

Via: 通过:

// 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>{});
}

This is nice because you get all the SFINAE without any of the enable_if cruft. 这很好,因为你得到的所有SFINAE都没有任何enable_if cruft。

One possible way is to add is_vector trait (look here for more details): 一种可能的方法是添加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 {};

And then modify your convertToString function templates as follows: 然后修改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 example wandbox示例

The template with errors marked: 标记错误的模板:

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

The template with errors fixed: 修复了错误的模板:

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