I am writing common function to convert type T to string:
when T is numeric type just use std::to_string
when others use stringstream operator <<
when T is std::string just 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);
}
}
test usage:
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
but compile error:
In instantiation of string to_str1 ..... no matching function for call to to_string(std::__cxx11::basic_string
I don't know why this error, ?
CodePudding user response:
When you write
if(std::is_integral<T>::value){
return to_str1(t);
}else{
return to_str2(t);
}
Then it is true that the if
condition is either always true or always false at runtime, but it is still required that the two branches can be compiled. The first branch however doesn't work with T = std::string
.
If you want to exclude branches from being compiled completely (aside from syntax check) based on a compile time constant, then you can use if constexpr
:
if constexpr(std::is_integral<T>::value){
return to_str1(t);
}else{
return to_str2(t);
}
This tells the compiler to check the if
condition at compile-time and only compile the branch that would be taken.
This requires C 17 or later.
CodePudding user response:
The problem is that both the if
and else
branch will be evaluated at compile-time; you can use Constexpr If (since 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);
}
}
Or overload to_str
with the help of SFINAE.
// 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;
}