15

I don't use C++11 yet, so I wrote the functions to_string(whatever) by myself. They should only be compiled if they don't exist. If I switch to C++11, they should be skipped. I have something like this:

#ifndef to_string

string to_string(int a){
    string ret;
    stringstream b;
    b << a;
    b >> ret;
    return ret;
}

string to_string(double a){
    string ret;
    stringstream b;
    b << a;
    b >> ret;
    return ret;
}

#endif

This doesn't work apparently. Is something like this possible and if yes, how?

MaestroGlanz
  • 321
  • 3
  • 12
  • It works pre-C++11, See http://cpp.sh/86ldr – Arnav Borborah Sep 03 '16 at 12:41
  • @ArnavBorborah Well, it shouldn't work. `std::to_string` is C++11 thing – xinaiz Sep 03 '16 at 12:43
  • Personally I think it's a very bad practice, and there is no good answer to this question. C++ standard doesn't provice `to_string`, but `std::to_string`, which is very different. That means, you can't use `std::to_string` if your standard doesn't support it. Now think again - let's assume that you already use C++11. What now? If you use macro from accepted answer, will you for the rest of your life use it instead of `std::to_string`? Very, very bad idea. – xinaiz Sep 03 '16 at 13:08
  • The reason that it doesn't work is that `#ifdef` only tests the presence of _preprocessor_ definitions, not of regular functions like `std::to_string`. And this is all that `#ifdef` can test, as preprocessor directives are executed by the ... preprocessor. – Marc van Leeuwen Sep 03 '16 at 21:29

5 Answers5

14

This is one of main purpose of namespace existence.

My suggest is to include your personal function in a proper namespace, something like:

namespace myns {
  std::string to_string(...) {
    // ...
  }
  // etc...
}

This is fundamental in order to avoid future conflict problems.

Afterwards, when you're going to use that function, you can simple select the proper function with a MACRO substitution.

Something like:

#if (__cplusplus >= 201103L) 
  #define my_tostring(X) std::to_string(X)
#else
  #define my_tostring(X) myns::to_string(X)
#endif

Note __cplusplus is a pre-defined macro which contains compiling information about standard version.


Edit:
Something less "violent", it will select the proper namespace for that specific function in accordance with the standard version:

#if (__cplusplus >= 201103L) 
  using std::to_string;
#else
  using myns::to_string;
#endif

// ... somewhere
to_string(/*...*/);  // it should use the proper namespace
BiagioF
  • 9,368
  • 2
  • 26
  • 50
  • 3
    `#if (__cplusplus >= 201103L) ` is what I needed. Thank's man. – MaestroGlanz Sep 03 '16 at 12:55
  • 6
    Rather than #define a macro, put an appropriate `using `ns`::to_string` in each branch of the `#ifdef` block. Less violence to your compiler name space. – Spencer Sep 03 '16 at 13:21
9

You can't test whether they're defined as such, but you can check the language version:

#if __cplusplus < 201103L

(There's a useful collection of predefined compiler macros here.)

molbdnilo
  • 64,751
  • 3
  • 43
  • 82
2

You could play with SFINAE having in mind that non-template overloads are preferred over the template ones. This compiles in both pre-c++11 and c++11:

#include <sstream>
#include <string>
#include <iostream>

using namespace std;

namespace my {
   template <bool V, class T>
   struct enable_if {
   };

   template <class T>
   struct enable_if<true, T> {
      typedef T type;
   };

   template <class T1, class T2>
   struct is_same {
      static const bool value = false;
   };

   template <class T>
   struct is_same<T, T> {
      static const bool value = true;
   };
}

template <class T>
typename my::enable_if<my::is_same<T, int>::value
                      || my::is_same<T, double>::value, string>::type
  to_string(T const& a) {
    string ret;
    stringstream b;
    b << a;
    b >> ret;
    return ret;
}

int main() {
   cout << to_string(2) << endl;
   cout << to_string(3.4) << endl;
}
W.F.
  • 13,888
  • 2
  • 34
  • 81
1

You can put your functions inside a macro, like this:

#ifndef to_string
#define to_string

//....

#endif

Then, in another file, write this:

#if __cplusplus >= 201103L
    #undef to_string
#else
    #define to_string
#endif
Arnav Borborah
  • 11,357
  • 8
  • 43
  • 88
  • 1
    The code doesn't need to check whether `to_string` is defined; `#undef` can be used with names that have not been defined. – Pete Becker Sep 03 '16 at 13:04
0

Boost.Config has some macros to check whether C++11 features are supported/used.

tux46
  • 1
  • 1