Строковый литерал в качестве аргумента шаблона
Эти препроцессорные и шаблонные ограничения C++ убивают меня. Цель состоит в том, чтобы преобразовать строковые литералы в целые числа.
template<const char* str>
inline int LiteralToInt(){
return __COUNTER__;
}
using std::cout;
int main(){
cout << LiteralToInt<"Hello">();
cout << LiteralToInt<"No">();
cout << LiteralToInt<"Hello">();
return 0;
}
Вывод будет 010, если шаблоны принимают строковые литералы. Есть ли другой способ получить этот вывод и преобразовать строковые литералы в целые числа во время компиляции?
4 ответа
К сожалению, я не знаю способа сделать именно то, что вы хотите.
Есть ли какие-то ограничения, которые вы можете наложить на строки? Как количество символов? Если вы можете ограничить его до 1-8 символов, вы можете сделать что-то вроде этого:
template <char Ch1, char Ch2 = '\0', char Ch3 = '\0', char Ch4 = '\0', char Ch5 = '\0', char Ch6 = '\0', char Ch7 = '\0', char Ch8 = '\0'>
struct string_hash {
static const uint64_t value =
(static_cast<uint64_t>(Ch1) << 56) |
(static_cast<uint64_t>(Ch2) << 48) |
(static_cast<uint64_t>(Ch3) << 40) |
(static_cast<uint64_t>(Ch4) << 32) |
(static_cast<uint64_t>(Ch5) << 24) |
(static_cast<uint64_t>(Ch6) << 16) |
(static_cast<uint64_t>(Ch7) << 8) |
(Ch8);
};
который в основном, во время компиляции вещи до 8
персонажи в uint64_t
, Использование будет выглядеть так:
const uint64_t x = string_hash<'T', 'e', 's', 't'>::value
Это создаст числовое значение времени компиляции (может использоваться в switch
и все такое совершенство) уникален для каждой строки длиной 1-8 символов. К сожалению, единственным большим недостатком является то, что вы не можете написать его в виде строкового литерала, вам нужно написать его в виде списка char
s
Да, C++ 11 constexpr
сделаю это для вас:
constexpr int LiteralToInt(const char * str) {
return __COUNTER__; // or whatever.
}
Примерно так будет работать
extern const char HELLO[] = "Hello";
а потом
cout << LiteralToInt<HELLO>();
но не сам буквальный. Это, вероятно, не то, что вы хотите.
Сами строковые литералы, как вы уже обнаружили, не могут использоваться в качестве аргументов шаблона.
Немного подумав об ответе Ричарда Дж. Росса III с использованием constexpr, я получил правильный ключ для поиска... Что вы по сути делаете, это хэширование строки во время компиляции. Вы можете сделать это в C++11 (но не в более ранних версиях), как показано здесь.
Основная идея состоит в том, чтобы использовать что-то вроде этого:
unsigned int constexpr const_hash(char const *input) {
// really simple hash function...
return static_cast<unsigned int>(*input)
&& static_cast<unsigned int>(*input) + hash(input+1);
}
Но вы, вероятно, хотите использовать хеш-функцию с более надежными свойствами, чем эта...
Однако, если вы не используете C++ 11, то мое предыдущее утверждение верно:
Нет - во время компиляции невозможно преобразовать строковые литералы в целые числа таким образом, чтобы все одинаковые строки отображались в одинаковые значения (и разные строки отображались в разные значения) во всех единицах компиляции, если не обрабатывать код каким-то образом.