1

I know,I know. This question seems to be asked several time. But all the answers are not exactly what I want because they do not resolve the whole thing at compile time. Or they are not working on the actual compiler trio VS,XCode and GCC (without #ifdefs) using C++11 features. Or at least, they lost me during explanation. So I tried on my own:

I tried to implement a method which I can give any type. As long as the type can be converted into a std::string by using std::to_string that should be used. If it is an object of a self-written class, it should have a "toString" method, than the method should use that. It would be fine if this decisions are made during compile time. Here where I come so far:

#include <stdio.h>
#include <iostream>
#include <string>

class Test
{
public:
    template <typename T> static auto has_toString_method(T& t) -> decltype(t.toString(), bool()) { return true; }
    static int has_toString_method(...) { return 0; }   

    template< class T> static void toString(T value)
    {
        toString(value,has_toString_method(value) );    
    }

    template< class T> static void toString(T value,bool)
    {
        value.toString();
    }

    template< class T,bool> static void toString(T value,int)
    {
        printf("It works with to_string");
    }
};


class MyToStringTest
{
public:
    void toString()
    {
        printf("It works toString");        
    }
};

int main ()
{
    MyToStringTest tst;

    Test::toString(5); // This fails because the compiler tries to resolve the bool arc.
    Test::toString(tst);

 return 0;
}  

Besides that this code is actually not compiling on VS2012 ( I marked the line ), it also is not a full decision on compile time ( I think). What I am missing? What is the fasted, smallest way to get this running?

As addon question. Is it possible, if there are "std::to_string" failing and the "toString" missing to assert or call a "third way"?

UPDATE:

I got the bug, running in circles I was copy and pasting a definition on the wrong place instead of:

    template< class T,bool> static void toString(T value,int)
    {

I have (of course)to write:

    template< class T> static void toString(T value,int)
    {

Than It will not only compile, it also will work! But the other questions will remain.

Martin Schlott
  • 4,369
  • 3
  • 25
  • 49

2 Answers2

1

This works:

#include <stdio.h>
#include <cstdint>
#include <iostream>
#include <string>

template<int i>
struct ToStringMethod {
  template<typename T>
  static void toString(T value) {
    printf("It works with 3rd method\n");
  }
};

template<>
struct ToStringMethod<1> {
  template<typename T>
  static void toString(T value)
  {
    value.toString();
  }
};

template<>
struct ToStringMethod<2> {
  template<typename T>
  static void toString(T value)
  {
    printf("It works with to_string\n");
  }
};

class Test
{
public:
    template <typename T> static auto has_string_support(T& t) -> decltype(t.toString(), std::int8_t()) { return true; }
    template <typename T> static auto has_string_support(T& t) -> decltype(std::to_string(t), std::int16_t()) { return true; }
    static std::uint32_t has_string_support(...) { return true; }   

    template< class T> static void toString(T value)
    {   
        ToStringMethod<sizeof(has_string_support(value))>::toString(value);    
    }   

};


class MyToStringTest
{
public:
    void toString()
    {   
        printf("It works toString\n");    
    }   
};

class NoneString {}; 

int main ()
{
    MyToStringTest tst;
    NoneString     none;

    Test::toString(5); // This fails because the compiler tries to resolve the bool arc.
    Test::toString(tst);
    Test::toString(none);

 return 0;
} 
Kariddi
  • 62
  • 1
  • 2
1

Following may help:

#include <string>
#include <type_traits>

#define HAS_MEM_FUNC(name, Prototype, func)                         \
    template<typename U>                                            \
    struct name {                                                   \
        typedef char yes[1];                                        \
        typedef struct { char dummy[2]; } no;                       \
        template <typename T, T> struct type_check;                 \
        template <typename T = U>                                   \
        static yes &chk(type_check<Prototype, &T::func> *);         \
        template <typename > static no &chk(...);                   \
        static bool const value = sizeof(chk<U>(0)) == sizeof(yes); \
    }

HAS_MEM_FUNC(has_to_string, std::string(T::*)() const, toString);


class Test
{
public:

    template<typename T>
    static typename std::enable_if<has_to_string<T>::value, std::string>::type
    toString(const T& t) {
       /* something when T has toString ... */
       return t.toString();
    }

    template<typename T>
    static typename std::enable_if<!has_to_string<T>::value, std::string>::type
    toString(const T& t) {
       /* something when T doesnt have toString ... */
       return std::to_string(t);
    }
};

class MyToStringTest
{
public:
    std::string toString() const
    {
        return "It works toString";
    }
};

int main(int argc, char** argv)
{
    MyToStringTest tst;

    Test::toString(5);
    Test::toString(tst);

    return 0;
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302