通过函数模板和SFINAE区分参数

3

我正在努力将函数模板分为三组:一组用于生成处理整数的函数,一组用于处理浮点数,另一组用于处理其它类型(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时出现错误:非类型模板参数非法;在类指针类型实例中使用static_not出现错误:“my::to_string:未找到匹配的重载函数”。
如果您能指点我正确的方向,请告诉我!我的目标是添加一个更快的实现(不需要为ostringstream实例分配内存)来处理整数类型,调整浮点数精度,并拥有一个处理其他类型的函数。最终版本可能不需要“negater”包装器,但我很好奇为什么它们不起作用。
编辑:我意识到我需要4个组,第四个是布尔值(因为布尔值也是整数类型)。因此,在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";
}
1个回答

4
这很简单。
#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
 }

非常感谢,工作得很好。有趣的是,我几乎没有遇到过在类型特征中使用这种布尔逻辑的例子,包括Bjarne的参考书。 - MatrixAndrew
1
为什么不使用 std::enable_if<! std::is_integral<T>::value && ! std::is_floating_point<T>::value 而不是 (false == ...) - em2er
@em2er - 嗯...我想这是个人口味的问题,但是在阅读时,我发现false == variable!variable更清晰。 - max66

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接