Search code examples
c++templatestemplate-meta-programmingsfinaeresult-of

Metaprograming: Failure of Function Definition Defines a Separate Function


In this answer I define a template based on the type's is_arithmetic property:

template<typename T> enable_if_t<is_arithmetic<T>::value, string> stringify(T t){
    return to_string(t);
}
template<typename T> enable_if_t<!is_arithmetic<T>::value, string> stringify(T t){
    return static_cast<ostringstream&>(ostringstream() << t).str();
}

dyp suggests that rather than the is_arithmetic property of the type, that whether to_string is defined for the type be the template selection criteria. This is clearly desirable, but I don't know a way to say:

If std::to_string is not defined then use the ostringstream overload.

Declaring the to_string criteria is simple:

template<typename T> decltype(to_string(T{})) stringify(T t){
    return to_string(t);
}

It's the opposite of that criteria that I can't figure out how to construct. This obviously doesn't work, but hopefully it conveys what I'm trying to construct:

template<typename T> enable_if_t<!decltype(to_string(T{})::value, string> (T t){
    return static_cast<ostringstream&>(ostringstream() << t).str();
}

Solution

  • Freshly voted into the library fundamentals TS at last week's committee meeting:

    template<class T>
    using to_string_t = decltype(std::to_string(std::declval<T>()));
    
    template<class T>
    using has_to_string = std::experimental::is_detected<to_string_t, T>;
    

    Then tag dispatch and/or SFINAE on has_to_string to your heart's content.

    You can consult the current working draft of the TS on how is_detected and friends can be implemented. It's rather similar to can_apply in @Yakk's answer.