Search code examples
c++templatessfinaeenable-if

SFINAE fallback when a function does not exist


I'm currently trying to implement a toString function which calls .toString() or std::to_string() depending on which is available for the deduced type

So far I have this working snippet:

#include <iostream>
#include <string>

template <class T>
auto toString(const T& obj)
        -> decltype(obj.toString(), std::string())
{
  return obj.toString();
}

template <class T>
auto toString(const T& obj)
        -> decltype(std::to_string(obj), std::string())
{
  return std::to_string(obj);
}

template <class T>
auto toString(const T& obj)
        -> decltype(std::string(obj))
{
  return std::string(obj);
}

class Foo{
public:
  std::string toString() const {
    return "Hello";
  }
};

int main()
{
  Foo bar;
  std::cout << toString(bar);
  std::cout << toString(5);
  std::cout << toString("Hello const char*");
}

Now I want to insert a static_assert when no overload from those above is viable, because the default GCC error message for older GCC versions is not very informative.

How can I check if neither .toString() nor std::to_string() are possible for T?

So far I found no way to check if something is not present, only the other way around. I hope someone has an idea how to solve this and thanks for your time.


Solution

  • You can also use static_assert with a custom error message:

    class Dummy
    {
    public:
        std::string toString() const;    
    private:
        Dummy() = default;
    };
    
    template <typename... Ts>
    auto toString(Ts...)
    {
        static_assert(std::is_same<std::tuple<Ts...>, std::tuple<Dummy>>::value, "neither std::to_str nor member toString() exists");
        return "";
    }
    

    live example