Android ndk std::to_string support
Asked Answered
B

6

48

I'm using android NDK r9d and toolchain 4.8 but I'm not able to use std::to_string function, compiler throws this error:

 error: 'to_string' is not a member of 'std'

Is this function not supported on android ndk? I try APP_CPPFLAGS := -std=c++11 with no luck.

Balliol answered 31/3, 2014 at 23:18 Comment(0)
D
62

You can try LOCAL_CFLAGS := -std=c++11, but note that not all C++11 APIs are available with the NDK's gnustl. Full C++14 support is available with libc++ (APP_STL := c++_shared).

The alternative is to implement it yourself.

#include <string>
#include <sstream>

template <typename T>
std::string to_string(T value)
{
    std::ostringstream os ;
    os << value ;
    return os.str() ;
}

int main()
{
    std::string perfect = to_string(5) ;
}
Deutschland answered 1/4, 2014 at 1:32 Comment(7)
I make some tries with no luck (LOCAL_CPPFLAGS += -std=c++11, LOCAL_CPPFLAGS += -std=gnu+11 etc.), and also I found some answers (#17951314) which explains that ndk not supports new c++11 string function, so finally I implement to_string method as you suggests. Thanks :).Balliol
I have tried it but gives error on std::ostringstream. The issue might be about Android Studio 2.2 alpha 6. Is there any easy way to convert?Haze
Extremely helpful all for compilers that don't support C++11. BTW: Is there a way (a macro definition) to check if C++11 is present, to skip this?Pallbearer
I just found the char template specializations missing, you need 3 of them, for: char, signed char, unsigned charPallbearer
I have used the same function but application get crash for some devices with below log libloglib-jni.so 0xdd7bdacf std::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >::~basic_ostringstream() (basic_ios.h:276) 36 libart.so 0xf4832812 (Missing) 37 libloglib-jni.so 0xdd7a5851 std::string patch::to_string<int>(int const&) can you please provide any solution if you have.Wirra
I've updated the answer to account for modern NDKs, and also clarified the situations where the C++11 APIs were missing.Fantasm
Better to pass value by const reference: std::string to_string(const T& value)Dreamworld
R
26

With NDK r9+ you can use llvm-libc++ which offers full support for cpp11.

In your Application.mk you have to add:

APP_STL:=c++_static 

or

APP_STL:=c++_shared
Rushton answered 19/12, 2014 at 9:33 Comment(7)
using cocos2d-x this worked to get around the std::to_string compile issue. However it caused other build problems down stream: "error: 'pthread_key_t' does not name a type static pthread_key_t s_threadKey" In case some tries this. I was never able to solve that. As mentioned here #22165064 changing compilers led to other compile issues... The accepted answer got around the issue in the short term...Radiogram
@Hunter I didn't mention that on my question however I was using cocos2d, and the accepted answer is simply an clean and as you said got around the issue so this is why I did accept it :)Balliol
Yes I too went with the accepted answer, I was not able to figure out exactly how to use this approach correctly. I was missing other threading libs. Probably could have done it if I spent more time... I just wanted that specific error here so if I ever run into this again I will have a hit right away :)Radiogram
I was looking for this one for hours, so thank you thursdaysDove!Doriedorin
I also get other errors down stream with this answer.Totter
@thursdaysDove, +1. Working fine when the flag added to the application.mk file. As expected i am able to compile from the terminal window using ndk-build. But i am not able to do this from eclipse (enable with android). There i am getting error on the to_string function. Do you have any idea which file need to be included?Loriannlorianna
This breaks ABI compatibility with any static libraries compiled (e.g. third party libs). So you'll have to rebuild them again. Would be nice to avoid that.Finstad
W
13

Gradle

If you looking for solution for Gradle build system. Look at this answer.

Short answer.

Add the string

arguments "-DANDROID_STL=c++_shared"

in your build.gradle. Like

android {
  ...
  defaultConfig {
    ...
    externalNativeBuild {
      cmake {
        ...
        arguments "-DANDROID_STL=c++_shared"
      }
    }
  }
  ...
}
Whooper answered 12/1, 2017 at 18:35 Comment(1)
Actually this is the only valid answer ,given that today's native development for Android is mostly done with Android Studio which uses Gradle.Disoperation
H
1

Experimental Gradle Plugin

If you're looking for a solution for the Experimental Gradle plugin, this worked for me...

Tested with com.android.tools.build:gradle-experimental:0.9.1

model {
  ...
  android {
    ...
    ndk {
      ...
      stl = "c++_shared"
    }
  }
}
Hit answered 16/5, 2017 at 2:30 Comment(0)
A
0

I could not use c++_static, it gave some errors about undefined exceptions. So I returned to the gnustl_static.

But in NDK sources, in sources/cxx-stl/llvm-libc++/src/string.cpp, I found implementation of to_string(int) and tried to copy it to my code. After some corrections it worked.

So the final piece of code I had:

#include <string>
#include <algorithm>

using namespace std;


template<typename S, typename P, typename V >
inline
S
as_string(P sprintf_like, S s, const typename S::value_type* fmt, V a)
{
    typedef typename S::size_type size_type;
    size_type available = s.size();
    while (true)
    {
        int status = sprintf_like(&s[0], available + 1, fmt, a);
        if ( status >= 0 )
        {
            size_type used = static_cast<size_type>(status);
            if ( used <= available )
            {
                s.resize( used );
                break;
            }
            available = used; // Assume this is advice of how much space we need.
        }
        else
            available = available * 2 + 1;
        s.resize(available);
    }
    return s;
}

template <class S, class V, bool = is_floating_point<V>::value>
struct initial_string;

template <class V, bool b>
struct initial_string<string, V, b>
{
    string
    operator()() const
    {
        string s;
        s.resize(s.capacity());
        return s;
    }
};

template <class V>
struct initial_string<wstring, V, false>
{
    wstring
    operator()() const
    {
        const size_t n = (numeric_limits<unsigned long long>::digits / 3)
          + ((numeric_limits<unsigned long long>::digits % 3) != 0)
          + 1;
        wstring s(n, wchar_t());
        s.resize(s.capacity());
        return s;
    }
};

template <class V>
struct initial_string<wstring, V, true>
{
    wstring
    operator()() const
    {
        wstring s(20, wchar_t());
        s.resize(s.capacity());
        return s;
    }
};

string to_string(int val)
{
    return as_string(snprintf, initial_string<string, int>()(), "%d", val);
}
Armond answered 25/1, 2018 at 20:40 Comment(0)
V
0

For Android Studio, add this in build.gradle (Mobile App)

externalNativeBuild {
    cmake {
        cppFlags "-std=c++11"

        arguments "-DANDROID_STL=c++_static"
    }
}
Vamp answered 22/6, 2018 at 9:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.