c++ 字符串模板没有匹配函数来调用 basic_string<char>

c++ string template no matching function for call to basic_string<char>

我正在编写将类型 T 转换为字符串的通用函数:

  1. 当T是数字类型时就用std::to_string

  2. 当别人使用stringstream操作符时<<

  3. 当 T 是 std::string 只是 return T

template <typename Numeric>
string to_str1(Numeric n){
    return std::to_string(n);
}

template <typename NonNumeric>
std::string to_str2(const NonNumeric& v){
    std::stringstream ss;
    ss << v;
    return ss.str();
}

// if T is string just return
std::string to_str2(const std::string& v){
    return v;
}

template<typename T>
string to_str(const T& t){
    if(std::is_integral<T>::value){
        return to_str1(t);
    }else{
        return to_str2(t);
    }
}

测试用法:

int a = 1101;
cout << to_str(a) << endl;

string s = "abc";
cout << to_str(s) << endl;  // should use to_str2(const std::string& v),but compile error

但是编译错误:

在字符串实例化中 to_str1 ..... 没有匹配函数调用 to_string(std::__cxx11::basic_string

我不知道为什么会出现这个错误,?

写的时候

if(std::is_integral<T>::value){
    return to_str1(t);
}else{
    return to_str2(t);
}

那么确实if条件在运行时要么一直为真,要么一直为假,但是还是要求两个分支都能编译通过。然而,第一个分支不适用于 T = std::string.

如果你想根据编译时间常数完全排除分支编译(除了语法检查),那么你可以使用 if constexpr:

if constexpr(std::is_integral<T>::value){
    return to_str1(t);
}else{
    return to_str2(t);
}

这告诉编译器在编译时检查 if 条件,并且只编译将采用的分支。

这需要 C++17 或更高版本。

问题是 ifelse 分支都将在编译时求值;你可以使用 Constexpr If (C++17 起).

If the value is true, then statement-false is discarded (if present), otherwise, statement-true is discarded.

template<typename T>
string to_str(const T& t){
    if constexpr (std::is_integral<T>::value){
        return to_str1(t);
    }else{
        return to_str2(t);
    }
}

或在 SFINAE 的帮助下重载 to_str

// for integral-numbers
template <typename T>
typename std::enable_if<std::is_integral<T>::value, std::string>::type
to_str(T n){
    return std::to_string(n);
}

// for non-integral-numbers
template <typename T>
typename std::enable_if<!std::is_integral<T>::value, std::string>::type
to_str(const T& v){
    std::stringstream ss;
    ss << v;
    return ss.str();
}

// if T is string just return
std::string to_str(const std::string& v) {
    return v;
}