Подтвердить что ты не робот

Использование "constexpr" для использования строкового литерала для параметра шаблона

Я написал код для перевода 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, которая использует функцию FHV Hash. И таким образом он создает интегральный хэш для const char *, который, мы надеемся, является уникальным.

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

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

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

4b9b3361

Ответ 1

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

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

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

// 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

Ответ 2

Вот шаблон, который я использую для параметров string const string. class F { static constexpr const char conststr[]= "some const string"; TemplateObject<conststr> instance; };

см. fooobar.com/info/217939/...