#c #variables #scope
#c #переменные #область видимости
Вопрос:
РЕДАКТИРОВАТЬ: я обновил код, надеюсь, теперь он более конкретный. В основном я пытался извлечь функции с помощью библиотеки dlib. Мне нужно использовать хэш-таблицу vocab в функции get_features (которая находится внутри определения класса), но я хочу присвоить значения vocab перед переходом к функции get_features, как указано в коде, который не работает. Класс feature_extractor определяется библиотекой dlib. Я новичок как в c , так и в dlib, и на самом деле я не знаю, как лучше сформулировать свой вопрос.
Теперь мой код имеет следующую структуру:
#include <iostream>
#include <dlib/svm_threaded.h>
using namespace std;
using namespace dlib;
/*
* Read a vocabulary file and return a map of vocab
* ex. vocab["word-1"] = 0, vocab["word 0"] = 1, vocab["word 1"] = 2
*/
std::map<std::string,int> getVocab() {
std::map<std::string, int> vocab;
std::vector<string> words;
ifstream infile("filename");
string line;
while (getline(infile, line)) {
words.push_back(line);
}
int cnt = 0;
for (auto w : words) {
vocab[w] = cnt;
cnt ;
}
return vocab;
}
class feature_extractor {
public:
typedef std::vector<std::string> sequence_type;
std::map<std::string, int> vocab = getVocab(); // if put here, it does NOT work.
void get_features (
feature_setteramp; set_feature,
const sequence_typeamp; sentence,
unsigned long position
) const
{
std::map<std::string, int> vocab = getVocab(); // if put here, it works.
set_feature(vocab[sentence[position]]);
}
}
int main() {
// other stuff
structural_sequence_segmentation_trainer<feature_extractor> trainer;
sequence_segmenter<feature_extractor> segmenter = trainer.train(samples, segments);
// other stuff
}
Есть ли способ, которым я могу использовать хэш-таблицу в функции get_features без вызова getVocab внутри get_features? То есть vocab
присвоение переменной значения перед функцией get_features и использование его внутри функции.
Я попытался вызвать f1 в определении класса перед f2 и присвоить хеш-таблицу переменной, но, похоже, это не работает. Любая помощь была бы очень признательна.
Комментарии:
1. Почему это отклоняется?
2. @Rodger Почему вы проголосовали за это? Есть веские доводы?
3. Да, это хороший вопрос. Я тоже не знаю, как это сделать. Код представлен, в нем будет четкий ответ и т.д.
4. @WhozCraig Я добавил строку кода, как указано в комментариях, и попробую то, что вы предложили
5. @Хай ок. теперь это имеет смысл. Я думаю, вам просто нужен модифицированный конструктор по умолчанию..
Ответ №1:
Хеджирование ставки Я понимаю вашу проблему, есть несколько способов, которыми вы могли бы это сделать. Один из них приведен ниже:
- Определите альтернативный конструктор по умолчанию.
- В списке инициализации элемента указанного-же инициализируйте
vocab
из результатаgetVocab()
.
Вот и все. Это будет выглядеть примерно так:
class feature_extractor {
public:
typedef std::vector<std::string> sequence_type;
std::map<std::string, int> vocab;
// constructor added here.
feature_extractor() : vocab(getVocab()) // <=== member initialized
{
}
// ... rest of your code ...
};
Предыдущий код также будет участвовать в семантике перемещения, что также должно облегчить ненужное копирование.
В качестве альтернативы вы можете создать объект vocab в getVocab()
статическом var, объявить результат функции как ссылочный тип (вероятно const
) и загружать файл только изначально, если значение static vocab.empty()
равно true . Например:
std::map<std::string,int> constamp; getVocab()
{
static std::map<std::string, int> vocab;
if (vocab.empty())
{
std::vector<std::string> words;
std::ifstream infile("filename");
std::string line;
while (getline(infile, line)) {
words.push_back(line);
}
int cnt = 0;
for (auto w : words) {
vocab[w] = cnt;
cnt ;
}
}
return vocab;
}
Делая это, все пользователи getVocab()
получат одну и ту же ссылку на объект. Безопасность потоков может стать проблемой, поэтому в этом случае потребуется дополнительная работа, но, надеюсь, вы поняли идею. Вы также можете объединить это с предыдущими методами и сделать vocab
переменную-член постоянной ссылкой, а не конкретным объектом. В этом случае все экстракторы будут использовать одну и ту же ссылку на один и тот же статический vocab
объект в теле getVocab()
:
class feature_extractor {
public:
typedef std::vector<std::string> sequence_type;
std::map<std::string, int> constamp; vocab; // note: reference
// constructor added here.
feature_extractor() : vocab(getVocab()) // <=== member initialized
{
}
// ... rest of your code ...
};
Как я уже сказал, существует несколько способов сделать это. Какой из них зависит от того, что лучше всего соответствует вашему шаблону использования.
Комментарии:
1. Спасибо за предоставление нескольких решений. Я попробовал оба метода. Каким-то образом я должен инициализировать член внутри конструктора :
feature_extractor() {vocab = getVocab();}
… Но теперь это работает.2. @Hai Нет проблем. Синтаксис для использования инициализации члена показан в обоих приведенных мною примерах. Я бы посоветовал сделать это, особенно в последнем случае, когда это не предложение; это обязательно (ссылки всегда должны быть инициализированы). Желаю удачи.
Ответ №2:
Я понял, что вы хотите использовать функцию getVocab для инициализации члена вашего класса feature_extractor . Вы можете сделать это в конструкторе (как предложено WhozCraig). Вы также можете сделать функцию getVocab частью того же класса, если они логически связаны, и если вам это нужно только для того, чтобы она не попадала в глобальное пространство имен. Например,:
class feature_extractor {
private:
std::map<std::string, int> getVocab() {
// your code
}
public:
typedef std::vector<std::string> sequence_type;
std::map<std::string, int> vocab ;
feature_extractor()
{
vocab = getVocab();
}
};
Комментарии:
1. Спасибо. В конечном счете я определил функцию внутри определения класса, а также использовал конструктор.
Ответ №3:
Я не понял, что вы склонны делать, но вы можете объявить свою хэш-таблицу вне своих функций как глобальную переменную, что не рекомендуется.