Использование & quot; constexpr & quot; использовать строковый литерал для параметра шаблона

Я написал код для каста const char* в int используя constexpr и, таким образом, я могу использовать const char* в качестве аргумента шаблона. Вот код:

#include <iostream>

class conststr
{
public:
template<std::size_t N>
constexpr conststr(const char(&STR)[N])
:string(STR), size(N-1)
{}

constexpr conststr(const char* STR, std::size_t N)
:string(STR), size(N)
{}

constexpr char operator[](std::size_t n)
{
return n < size ? string[n] : 0;
}

constexpr std::size_t get_size()
{
return size;
}

constexpr const char* get_string()
{
return string;
}

//This method is related with Fowler–Noll–Vo hash function
constexpr unsigned hash(int n=0, unsigned h=2166136261)
{
return n == size ? h : hash(n+1,(h * 16777619) ^ (string[n]));
}

private:
const char* string;
std::size_t size;
};

// output function that requires a compile-time constant, for testing
template<int N> struct OUT
{
OUT() { std::cout << N << '\n'; }
};

int constexpr operator "" _const(const char* str, size_t sz)
{
return conststr(str,sz).hash();
}

int main()
{
OUT<"A dummy string"_const> out;
OUT<"A very long template parameter as a const char*"_const> out2;
}

В этом примере кода тип out является OUT<1494474505> и тип out2 является OUT<106227495>, Волшебство за этим кодом conststr::hash() это constexpr рекурсия, которая использует FNV хэш-функция. И, таким образом, он создает интегральный хеш для const char *, который, мы надеемся, является уникальным.

У меня есть несколько вопросов об этом методе:

  1. Это безопасный подход к использованию? Или этот подход может быть злом в конкретном использовании?
  2. Можете ли вы написать лучшую хеш-функцию, которая создает разные целые числа для каждой строки, не ограничиваясь количеством символов? (в моем методе длина достаточно велика)
  3. Можете ли вы написать код, который неявно приводит const char* в int constexpr с помощью conststr и, таким образом, нам не понадобится эстетически некрасиво (а также потребителю времени) _const пользовательский строковый литерал? Например OUT<"String"> будет допустимым (и приведение «String» к целому числу).

Любая помощь будет оценена, спасибо большое.

27

Решение

Хотя ваш метод очень интересен, на самом деле это не способ передачи строкового литерала в качестве аргумента шаблона. Фактически, это генератор аргумента шаблона, основанный на строковом литерале, который не совпадает: вы не можете получить string от hashed_string… Это побеждает весь интерес строковых литералов в шаблонах.

РЕДАКТИРОВАТЬ : следующее было правильным, когда использованный хеш был взвешенной суммой букв, что не имеет места после редактирования OP.

Вы также можете иметь проблемы с вашим хэш-функция, как указано в ответе Митчнулла. Это может быть еще одна большая проблема с вашим методом, столкновения. Например:

// Both outputs 3721
OUT<"0 silent"_const> out;
OUT<"7 listen"_const> out2;

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

struct string_holder              //
{                                 // All of this can be heavily optimized by
static const char* asString() // the compiler. It is also easy to generate
{                             // with a macro.
return "Hello world!";    //
}                             //
};                                //

Затем я передаю «фиктивный строковый литерал» через аргумент типа:

template<typename str>
struct out
{
out()
{
std::cout << str::asString() << "\n";
}
};

EDIT2: Вы сказали, что в комментариях вы использовали это, чтобы различать несколько специализаций шаблона класса. Показанный вами метод подходит для этого, но вы также можете использовать теги:

// tags
struct myTag {};
struct Long {};
struct Float {};

// class template
template<typename tag>
struct Integer
{
// ...
};
template<> struct Integer<Long> { /* ... */ };

// use
Integer<Long> ...;  // those are 2
Integer<Float> ...; // different types
13

Другие решения

Вот шаблон, который я использую для шаблонных строковых параметров.

class F {
static constexpr const char conststr[]= "some const string";
TemplateObject<conststr> instance;
};

увидеть :
https://stackoverflow.com/a/18031951/782168

6

По вопросам рекламы [email protected]