用函数模板和SFINAE按参数区分
Distinguishing by parameters with function templates and SFINAE
我正在努力将函数模板分解为三组:一组生成采用积分的函数,一组采用浮点数,另一组采用任何其他函数(ostringstream::<<
接受)。到目前为止,我什至不能做到有两组,像这样:
namespace my {
template<typename T>
struct logical_not
:
std::integral_constant<bool, !T::value>
{};
template <typename T>
using static_not = typename std::conditional<
T::value,
std::false_type,
std::true_type
>::type;
template<typename T>
std::string to_string(
const T& val,
typename std::enable_if< std::is_integral<T>::value >::type* = 0)
{
// integral version (ostringstream method would be replaced by a simple algorithm that forms a string)
std::ostringstream os;
os << val;
return os.str();
}
template<typename T>
std::string to_string(
const T& val,
//typename std::enable_if< logical_not<std::is_integral<T>>::type >::type* = 0)
typename std::enable_if< static_not<std::is_integral<T>> >::type* = 0)
{
std::ostringstream os;
os.flags(std::ios::fixed);
os.precision(2);
os << val;
return os.str();
}
} // my
我从其他答案中复制了两个取反函数,我就这样留下了它们的名字,这样更容易区分。我发现类型特征令人难以置信的混乱,我认为我得到的 logical_not 错误是对特定否定包装器的错误使用。
logical_not 错误是 Illegal type for non-type template parameter
并且 static_not 在 class 指针类型的实例中: 'my::to_string': no matching overloaded function found
.
如果可以的话,请告诉我正确的方向!我的观点是为整数类型添加一个更快的实现(不为 ostringstream 实例分配),使用浮点数调整精度并具有处理其他类型的函数。最终版本很可能不需要 "negater" 包装器,但我很好奇为什么它们不起作用。
编辑:
我意识到我需要 4 个组,第 4 个是 boolan(因为 boolen 也是一个整数类型)。因此,在 max66 的答案之上,修改一个函数并添加另一个函数,实现了预期的功能:
template<typename T>
std::string to_string(
const T& val,
typename std::enable_if<
std::is_same<bool, T>::value
>::type* = 0)
{
return val ? "true" : "false";
}
template<typename T>
std::string to_string(
const T& val,
typename std::enable_if<
std::is_integral<T>::value
&& (false == std::is_same<bool, T>::value)
>::type* = 0)
{
return "integral, but not bool";
}
比你想象的要简单。
#include <string>
#include <iostream>
#include <type_traits>
template<typename T>
std::string to_string(
const T& val,
typename std::enable_if< std::is_integral<T>::value
>::type * = nullptr)
{ return "case integral"; }
template<typename T>
std::string to_string(
const T& val,
typename std::enable_if< std::is_floating_point<T>::value
>::type * = nullptr)
{ return "case floating"; }
template<typename T>
std::string to_string(
const T& val,
typename std::enable_if< (false == std::is_integral<T>::value)
&& (false == std::is_floating_point<T>::value)
>::type * = nullptr)
{ return "case generic"; }
int main ()
{
std::cout << to_string(0) << std::endl; // print case integral
std::cout << to_string(0.0) << std::endl; // print case float
std::cout << to_string("0.000") << std::endl; // print case generic
}
我正在努力将函数模板分解为三组:一组生成采用积分的函数,一组采用浮点数,另一组采用任何其他函数(ostringstream::<<
接受)。到目前为止,我什至不能做到有两组,像这样:
namespace my {
template<typename T>
struct logical_not
:
std::integral_constant<bool, !T::value>
{};
template <typename T>
using static_not = typename std::conditional<
T::value,
std::false_type,
std::true_type
>::type;
template<typename T>
std::string to_string(
const T& val,
typename std::enable_if< std::is_integral<T>::value >::type* = 0)
{
// integral version (ostringstream method would be replaced by a simple algorithm that forms a string)
std::ostringstream os;
os << val;
return os.str();
}
template<typename T>
std::string to_string(
const T& val,
//typename std::enable_if< logical_not<std::is_integral<T>>::type >::type* = 0)
typename std::enable_if< static_not<std::is_integral<T>> >::type* = 0)
{
std::ostringstream os;
os.flags(std::ios::fixed);
os.precision(2);
os << val;
return os.str();
}
} // my
我从其他答案中复制了两个取反函数,我就这样留下了它们的名字,这样更容易区分。我发现类型特征令人难以置信的混乱,我认为我得到的 logical_not 错误是对特定否定包装器的错误使用。
logical_not 错误是 Illegal type for non-type template parameter
并且 static_not 在 class 指针类型的实例中: 'my::to_string': no matching overloaded function found
.
如果可以的话,请告诉我正确的方向!我的观点是为整数类型添加一个更快的实现(不为 ostringstream 实例分配),使用浮点数调整精度并具有处理其他类型的函数。最终版本很可能不需要 "negater" 包装器,但我很好奇为什么它们不起作用。
编辑: 我意识到我需要 4 个组,第 4 个是 boolan(因为 boolen 也是一个整数类型)。因此,在 max66 的答案之上,修改一个函数并添加另一个函数,实现了预期的功能:
template<typename T>
std::string to_string(
const T& val,
typename std::enable_if<
std::is_same<bool, T>::value
>::type* = 0)
{
return val ? "true" : "false";
}
template<typename T>
std::string to_string(
const T& val,
typename std::enable_if<
std::is_integral<T>::value
&& (false == std::is_same<bool, T>::value)
>::type* = 0)
{
return "integral, but not bool";
}
比你想象的要简单。
#include <string>
#include <iostream>
#include <type_traits>
template<typename T>
std::string to_string(
const T& val,
typename std::enable_if< std::is_integral<T>::value
>::type * = nullptr)
{ return "case integral"; }
template<typename T>
std::string to_string(
const T& val,
typename std::enable_if< std::is_floating_point<T>::value
>::type * = nullptr)
{ return "case floating"; }
template<typename T>
std::string to_string(
const T& val,
typename std::enable_if< (false == std::is_integral<T>::value)
&& (false == std::is_floating_point<T>::value)
>::type * = nullptr)
{ return "case generic"; }
int main ()
{
std::cout << to_string(0) << std::endl; // print case integral
std::cout << to_string(0.0) << std::endl; // print case float
std::cout << to_string("0.000") << std::endl; // print case generic
}