Android NDK Error: no matching member function for call to 'push_back'?

Возникла проблема во время портирования своей игры на андроид. Компилятор Android NDK ругается на эту строку:
if(b==13) rock.push_back({(uint16_t)(x*64),(uint16_t)(y*64),0,0});

Вывод компилятора:
spoiler
FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:externalNativeBuildDebug'.
> Build command failed.
  Error while executing process /Android/NDK/ndk-build with arguments {NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=/media/files/Android/project/app/jni/Android.mk NDK_APPLICATION_MK=/media/files/Android/project/app/jni/Application.mk APP_ABI=mips NDK_ALL_ABIS=mips NDK_DEBUG=1 APP_PLATFORM=android-14 NDK_OUT=/media/files/Android/project/app/build/intermediates/ndkBuild/debug/obj NDK_LIBS_OUT=/media/files/Android/project/app/build/intermediates/ndkBuild/debug/lib APP_PLATFORM=android-14 /media/files/Android/project/app/build/intermediates/ndkBuild/debug/obj/local/mips/libmain.so}
  /media/files/Android/NDK/build/core/setup-app.mk:81: Android NDK: Application targets deprecated ABI(s): mips    
  /media/files/Android/NDK/build/core/setup-app.mk:82: Android NDK: Support for these ABIs will be removed in a future NDK release.    
  Android NDK: WARNING: Unsupported source file extensions in /media/files/Android/project/app/jni/src/Android.mk for module main    
  Android NDK:   FC/SDL_FontCache.h    
  [mips] Compile++      : main <= main.cpp
  In file included from /media/files/Android/project/app/jni/src/main.cpp:1:
  In file included from /media/files/Android/project/app/jni/src/include.h:113:
  /media/files/Android/project/app/jni/src/game.cpp:45:39: error: no matching member function for call to 'push_back'
              if(b==13)            rock.push_back({(uint16_t)(x*64),(uint16_t)(y*64),0,0});
                                   ~~~~~^~~~~~~~~
  /media/files/Android/NDK/sources/cxx-stl/llvm-libc++/include/vector:677:36: note: candidate function not viable: cannot convert initializer list argument to 'const std::__ndk1::__vector_base<rck, std::__ndk1::allocator<rck> >::value_type' (aka 'const rck')
      _LIBCPP_INLINE_VISIBILITY void push_back(const_reference __x);
                                     ^
  /media/files/Android/NDK/sources/cxx-stl/llvm-libc++/include/vector:680:36: note: candidate function not viable: cannot convert initializer list argument to 'std::__ndk1::vector<rck, std::__ndk1::allocator<rck> >::value_type' (aka 'rck')
      _LIBCPP_INLINE_VISIBILITY void push_back(value_type&& __x);
                                     ^

класс rck:
class rck{
public:
    unsigned short x,y;
    void show();
    int tm=0;
    uint8_t type=0;
};
//////////////////////
std::vector<rck> rock;

НО! g++ прекрасно компилирует этот код, а Android NDK выдает ошибку. Почему так происходит и как исправить эту ошибку?
  • Вопрос задан
  • 112 просмотров
Решения вопроса 1
@MarkusD Куратор тега C++
все время мелю чепуху :)
class rck{
public:
    unsigned short x,y;
    void show();
    int tm=0;
    uint8_t type=0;
};

Вольное комментирование состояния кода
Тут у нас большие проблемы с читаемостью кода. stdint соседствует с сырыми конструкциями модификации типа, методы вперемешку с полями, класс вместо структуры, использование запятой при объявлении полей, имена в одну букву и акронимы. Неинициализированные поля - распространенный источник ошибок.

Лучше будет с молоду учиться правильно оформлять свой код. Например так.
struct rck final
{
	uint16_t x = 0;
	uint16_t y = 0;
	int32_t tm = 0;
	uint8_t type = 0;
	
	
	void show();
};

Не берусь менять имена, т.к. не понимаю их семантики. Каждое имя должно отражать семантику своего существования или должно быть стерто из кода.


У тебя объявлен, вроде бы, агрегатный тип с неявным конструктором по умолчанию, в котором выполняется инициализация только полей tm и type.

rock.push_back({(uint16_t)(x*64),(uint16_t)(y*64),0,0});

Тут перед обращением к push_back формируется фиктивный std::initializer_list<uint16_t> с двумя элементами внутри.
В общем смысле, до полного списка аргументов нужно указать еще два аргумента. Тогда эту запись можно будет считать агрегатной инициализацией временного объекта типа rck.

Такая форма агрегатной инициализации стандартизирована в C++11. До C++14 агрегатная инициализация отключается для типов, в которых присутствует инициализация полей по месту объявления (в коде это поля tm и type). Каждый следующий стандарт требования к агрегатной инициализации только ужесточает.

GCC давно славится своей слабой поддержкой стандарта языка. Это означает что если код проходит трансляцию g++, это далеко не факт что он соответствует стандарту.
NDK сегодня для сборки использует clang, который на данный момент считается максимально приближенным к стандарту транслятором.

Все это должно дать понять что данный код не соответствует стандарту языка и не должен компилироваться. Подходящего конструктора от двух аргументов для типа rck не определено и тип не является агрегатным.
То, что g++ смог собрать этот код, останется на совести g++.
Еще одним важным моментом будет точное понимание, какой именно стандарт языка выбран для трансляции твоего кода.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы