我已经编写了一些代码,使用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()
,它是使用FNV Hash function的constexpr
递归。因此它为const char *创建了一个完整的哈希值,希望它是一个独特的哈希值。
我对这个方法有一些疑问:
const char*
隐式地将int constexpr
强制转换为conststr
,因此我们不需要美观丑陋(以及时间消费者)_const
用户定义字符串字面量?例如,OUT<"String">
将是合法的(并将“String”转换为整数)。非常感谢任何帮助。
答案 0 :(得分:13)
虽然你的方法非常有趣,但它并不是一种将字符串文字作为模板参数传递的方法。实际上,它是一个基于字符串文字的模板参数的生成器,它不相同:你无法从string
中检索hashed_string
...它有点击败了模板中字符串文字的整体兴趣。
编辑:当使用的哈希值是字母的加权和时,以下情况是正确的,而在编辑OP后情况并非如此。
正如mitchnull的回答所述,您的hash function也可能出现问题。这可能是你的方法,碰撞的另一个大问题。例如:
// 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
答案 1 :(得分:6)
这是我用于模板const字符串参数的模式。
class F {
static constexpr const char conststr[]= "some const string";
TemplateObject<conststr> instance;
};