enable_if和多个条件的问题

Ove*_*ade 7 c++ templates sfinae enable-if c++14

我试图实现一个将泛型类型转换为字符串的函数.积分类型需要使用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;
}
Run Code Online (Sandbox Code Playgroud)

问题是第二个函数没有编译.如何设计第二个函数以便它编译(和工作)并且不会产生歧义问题?

Bar*_*rry 7

Oktalist的答案解释了为什么你的类型特征不能编译.此外,你不应该使用__and___not_.这些是保留的,可以在下一个编译器版本中轻松更改.实现这些特征的自己版本很容易(例如,参见可能的实现conjunction).

我建议采用完全不同的方法.我们可以使用choice<>这些更简单的方法来重载这些情况:

template <int I> struct choice : choice<I+1> { };
template <> struct choice<10> { };
Run Code Online (Sandbox Code Playgroud)

通过:

// 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>{});
}
Run Code Online (Sandbox Code Playgroud)

这很好,因为你得到了所有的SFINAE没有任何enable_if瑕疵.

  • @JustinTime`char`是算术,所以这符合OP的排序.虽然容易翻转. (2认同)

Edg*_*jān 5

一种可能的方法是添加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 {};
Run Code Online (Sandbox Code Playgroud)

然后修改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;
}
Run Code Online (Sandbox Code Playgroud)

wandbox示例