Я хочу иметь некоторую глобальную карту, которую следует использовать во многих местах, и несколько обычно используемых небольших функций. Вот как я пытаюсь его организовать.
util.h:
#ifndef UTIL_H
#define UTIL_H
#include <unordered_map>
namespace util {
extern std::unordered_map<std::string, short> rgb2short {
{ "000000", 0 },
{ "800000", 1 },
{ "008000", 2 },
{ "808000", 3 },
{ "000080", 4 },
/* ... and so on */
};
short some_util_func() {
/* some util code here */
}
}
#endif
somefile.cpp:
#include "util.h"
/* usage of util::rgb2short and util::some_util_func() */
someotherfile.cpp:
#include "util.h"
/* usage of util::rgb2short and util::some_util_func() */
Компилятор не принимал и не ответил многочисленными multiple definition of 'util::rgb2short'
и т.д.
Итак, вопрос в том, как лучше использовать эту вещь.
По крайней мере, когда дело доходит до данных, заголовок должен включать только объявление. Это объявление должно содержать ключевое слово extern
и (часть, которую вы сделали неправильно) не должна содержать инициализатор.
Единственное исключение из этого (и это не общий вообще) - это если вы хотите получить отдельную копию данных для каждой единицы перевода, в которую включен заголовок. В этом конкретном случае вам нужно указать, что данные являются static
а не extern
.
В вашем случае util.h
должен содержать только rgb2short
декларацию rgb2short
. Определение (включая инициализатор) должно быть в каком-то файле .cpp
(например, util.cpp
). Аналогично, util.h не должен включать определение some_util_func()
. Он должен включать только объявление и (опять же) определение, помещенное в исходный файл, такой как util.cpp
.
Итак, util.h будет выглядеть следующим образом:
#ifndef UTIL_H
#define UTIL_H
#include <unordered_map>
namespace util {
extern std::unordered_map<std::string, short> rgb2short;
short some_util_func();
}
#endif
Util.cpp будет выглядеть так:
#include "util.h"
namespace util {
std::unordered_map<std::string, short> rgb2short {
{ "000000", 0 },
{ "800000", 1 },
{ "008000", 2 },
{ "808000", 3 },
{ "000080", 4 },
/* ... and so on */
};
short some_util_func() {
/* some util code here */
}
}
Тогда вы бы #include "util.h"
же, как и вы, но также и ссылку util.obj
(или util.o или что-то вроде объектного файла) с другими объектными файлами.
Вы должны поместить объявление в заголовок и определение в исходный файл, например:
util.h
#ifndef UTIL_H
#define UTIL_H
#include <unordered_map>
namespace util {
extern std::unordered_map<std::string, short> rgb2short;
}
#endif
и в util.cpp:
#include "util.h"
namespace util {
std::unordered_map<std::string, short> rgb2short {
{ "000000", 0 },
{ "800000", 1 },
{ "008000", 2 },
{ "808000", 3 },
{ "000080", 4 },
/* ... and so on */
};
}
Это позволит избежать этих ошибок. Для функции отметьте ее как inline
и поместите код в заголовок или просто поместите подпись в заголовок (нет необходимости в extern
) и поместите тело в файл CPP.