使用"constexpr"将字符串文字用于模板参数

Equ*_*als 27 c++ templates string-literals constexpr c++11

我已经写了一些代码投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;
}
Run Code Online (Sandbox Code Playgroud)

在此示例代码中,outis的OUT<1494474505>类型和out2is的类型OUT<106227495>.这段代码背后的魔法是conststr::hash()它是一个constexpr使用FNV哈希函数的递归.因此它为const char*创建了一个完整的哈希值,希望它是一个独特的哈希值.

我对这个方法有一些疑问:

  1. 这是一种安全的使用方法吗?或者这种方法在特定用途中可能是邪恶的吗?
  2. 你能写一个更好的哈希函数,为每个字符串创建不同的整数,而不限于多个字符吗?(在我的方法中,长度足够长)
  3. 你能编写一个隐式转换const char*int constexprvia 的代码,conststr因此我们不需要美观丑陋(也是时间消费者)_const用户定义的字符串文字吗?例如,OUT<"String">将是合法的(并将"String"转换为整数).

任何帮助将不胜感激,非常感谢.

Syn*_*xis 13

尽管您的方法非常有趣,但它并不是一种将字符串文字作为模板参数传递的方法.实际上,它是一个基于字符串文字的模板参数的生成器,它不一样:你无法stringhashed_string...中检索它有点击败模板中字符串文字的整体利益.

编辑:当使用的哈希值是字母的加权和时,以下是正确的,这不是在编辑OP之后的情况.

正如mitchnull的回答所述,您也可能遇到哈希函数问题.这可能是你的方法,碰撞的另一个大问题.例如:

// Both outputs 3721
OUT<"0 silent"_const> out;
OUT<"7 listen"_const> out2;
Run Code Online (Sandbox Code Playgroud)

据我所知,您无法在当前标准中直接在模板参数中传递字符串文字.但是,你可以"假装"它.这是我一般使用的:

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!";    //
    }                             //
};                                //
Run Code Online (Sandbox Code Playgroud)

然后,我通过类型参数传递"伪字符串文字":

template<typename str>
struct out
{
    out()
    {
        std::cout << str::asString() << "\n";
    }
};
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)


h4c*_*1k3 6

这是我用于模板const字符串参数的模式. class F { static constexpr const char conststr[]= "some const string"; TemplateObject<conststr> instance; };

请参阅:https: //stackoverflow.com/a/18031951/782168