Parameter differences with function templates and SFINAE

I am breaking a sweat over templates of function calls to three groups: one to create functions that take integrals, one to accept floating points, and another to accept any others (which ostringstream::<<

takes). So far I can't even make it so that there are two groups, for example:

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

      

I copied two negative functions from other answers, I left their names so that it is easier to tell them apart. I find type traits incredibly confusing, I guess the error I am getting for logical_not is misuse of that particular negative wrapper.

With an error logical_not Illegal type for non-type template parameter

and static_not in the pointer type instance of the class: 'my::to_string': no matching overloaded function found

.

Please point me in the right direction if you can! I want to add a faster implementation (no highlighting for the ostringstream instance) for integral types, adjust the precision with floating points, and have a function that handles other types. The final version will most likely not need a "negator" wrapper, although I wonder why they won't work.

EDIT: I figured I would need 4 groups, the fourth is boolan (since boolen is also an integral type). Therefore, based on max66's answer, by changing one function and adding another, the intended functionality is achieved:

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";
}

      

+3


source to share


1 answer


It's easier than you think.



#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
 }

      

+4


source







All Articles