Как определить вложенную карту в заголовочном файле для использования в .cpp - PullRequest
0 голосов
/ 26 апреля 2019

Я пытаюсь определить вложенную переменную карты в заголовочном файле, который будет использоваться для поиска значения ключа (или ключа, поиска значения ключа, поскольку он вложен).

Извиняюсь за то, что очень плохо знаком с C ++ в целом, не говоря уже о C ++ 98. У меня есть средний опыт JavaScript, который может объяснить трудности / привычки.

Я пытаюсь вставить устные языковые переводы в пользовательский интерфейс, используя вложенную карту, что-то со структурой, подобной этой:

phrases["english"]["hello"] = "hi";
phrases["spanish"]["hello"] = "hola";

, что позволит мне использовать фразы [selectedLanguage] ["hello"], которые будут возвращать (?) "Hi" или "hola" в зависимости от того, на что установлен selectedLanguage.

Это сделано для того, чтобы пользователь мог переключаться между языками, а также позволял мне просто изменить один файл translations.h, если / когда это необходимо.

У меня есть рабочая версия кода, которая помещает определения карт в код .cpp, но я хотел бы создать что-то вроде заголовочного файла, который определяет мою переменную карты «фразы», ​​чтобы я мог отделить языковые переводы от остальная часть кода .cpp.

Мой текущий рабочий код выглядит так:

UI.cpp:

void CScnMgr::InitScreens(){

  // selectedLanguage is defined 
  string selectedLanguage = "spanish";

  //phrases map is defined
  map <string, map <string, string> > phrases;
  phrases["english"]["hello"] = "hi";
  phrases["spanish"]["hello"] = "hola";

  // then later when i need to use either translation...
  phrases[selectedLanguage]["hello"];
}

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

Это дает мне ошибки:

translations.h:

#include <string>
#include <map>

int main(){
  map <string, map <string, string> > newPhrases;
  map <string, string> spanish;
  map <string, string> english;

  spanish["hello"] = "hola";
  english["hello"] = "hi";

  newPhrases["spanish"] = spanish;
  newPhrases["english"] = english;
  return 0;
}

UI.cpp:

#include "translations.h"


void CScnMgr::InitScreens(){
  int extern newPhrases;

// further down where I need to display to the UI...
  newPhrases[selectedLanguage]["hi"]

}

Ошибка:

UI.cpp: error: no match for 'operator[]' in 'newPhrases[selectedLanguage]'

Я, конечно, не понимаю, почему вставка «int» в «int extern newPhrases» проходит компиляцию, но именно поэтому она есть, я дал ей тип возврата main (). Мне не очень удобно это делать.

Итак, я определил selectedLanguage как «английский», поэтому я ожидал, что C ++ будет обрабатывать это как newPhrases [«english»], но кажется, что newPhrases не определен, как я ожидаю, после импорта из переводов. ч

Я был бы признателен за способ заставить этот код работать, но я также оценил бы причины, по которым это неправильный путь. Заранее спасибо!

1 Ответ

0 голосов
/ 26 апреля 2019

Давайте попробуем это шаг за шагом:

JavaScript в C ++

Это довольно смелая задача :) Я думаю, вы выбрали сложный путь, идущий таким образом.Было бы проще наоборот.Ну ... это то, что есть.Позвольте мне сказать: C ++ чувствует себя совсем не так, как JavaScript.Я настоятельно рекомендую сделать одно из множества учебных пособий и / или прочитать хорошую книгу об этом.Есть много!

Структура файла

Вообще говоря, никогда не должно быть определений в заголовочных файлах, только объявления.Если вы хотите узнать больше об этом, google - ваш друг .

Что вы можете сделать , если у вас есть объявление в заголовочном файле(используя ключевое слово extern или помещая его в класс) и определение в (отдельный) файл cpp.Затем компоновщик найдет это определение и свяжет выходные данные.

OOP

Я настоятельно рекомендую ознакомиться с концепцией OO .Это, вероятно, поможет вам в долгосрочной перспективе, и могут быть более элегантные решения для вашей проблемы, но я не буду вдаваться в подробности здесь, см. Другие заголовки.

Анализ вашего текущего кода

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

    Проблема в том, что этот объект, который у вас есть, сейчас находится в стеке и вскоре будет уничтожен (перезаписан), когда вы покинетефункция.Так что это не будет работать, если вы хотите получить доступ к phrases из другой функции.Вы можете прочитать больше о времени жизни объекта здесь и немного больше о том, как scope связан с продолжительностью жизни в первой ссылке, которая появилась в Google .

  • Это дает мне ошибки:

    translations.h:

    #include <string>
    #include <map>
    
    int main(){
      map <string, map <string, string> > newPhrases;
      map <string, string> spanish;
      map <string, string> english;
    
      spanish["hello"] = "hola";
      english["hello"] = "hi";
    
      newPhrases["spanish"] = spanish;
      newPhrases["english"] = english;
      return 0;
    }
    

    Лучшая практика - не реализовывать вашифункции в заголовочных файлах, но только объявляйте их там и реализуйте в файлах cpp.Для main() вам не нужна декларация.Просто используйте файл cpp.

    Другое дело, что вы создаете newPhrases в стеке main(), поэтому newPhrases также действует только во время работы main().Вероятно, не то, что вы хотите.

  • UI.cpp:

    #include "translations.h"
    
    void CScnMgr::InitScreens(){
      int extern newPhrases;
    
    // further down where I need to display to the UI...
      newPhrases[selectedLanguage]["hi"]
    
    }
    

    Ошибки:

    UI.cpp: error: no match for 'operator[]' in 'newPhrases[selectedLanguage]'
    

    int extern newPhrases это просто декларация.Он сообщает компилятору, что есть что-то с именем newPhrases где-то (но не здесь) и что оно имеет тип int.На самом деле вы хотели бы сказать компилятору, что эта вещь имеет тип map<string, map<string, string> >.Кроме того, объявления extern не должны быть внутри функций.Сама ошибка исходит из вашей extern декларации.Компилятор считает, что newPhrases имеет тип int, но что-то типа int не имеет оператора квадратной скобки (operator[]).Но даже если вы исправите это, он не будет работать, поэтому я не буду вдаваться в подробности, как заставить что-то работать.(См. Некоторые предложения и ссылки в следующем разделе)

Общий подход к локализации / интернационализации / многоязыковой поддержке

Отношение к желанию абстрагировать языки разделение его из вашего кода это хорошо.Вопрос сейчас в том, как ее решить.Основная идиома в программировании в целом - «не изобретать велосипед» .

В принципе, я считаю ваш вопрос дубликатом к этому:
C ++, поддержка мультиязычности / локализации

Еще одна очень похожая тема, которую я обнаружил:
Как улучшить практику локализованного текста в кроссплатформенных приложениях C ++?

Еще один:
Как поддерживать несколько языков в программе Linux C / C ++?

Если вы хотите придерживаться своего подхода, взгляните на этот (производительность):
C ++ map vs map производительность (я знаю, «снова?»)

В постах, упомянутых выше, есть много предложений, а также фреймворки, которые могут довольно хорошо справиться с вашей проблемой. Я также рекомендую провести собственное исследование, потому что некоторые вопросы довольно старые, и, возможно, уже появилось что-то новое. Просто спросите вашего верного друга

...