模板非类型参数推导
Template non-type parameter deduction
是否可以推导出 c++17 函数的模板值(不是类型)?
函数 foo:
template<int I>
int foo()
{
return (I);
}
可以通过以下方式调用:
foo<5>();
并且会 return 5.
模板类型可以通过函数参数的类型推导出来。是否有可能以某种方式对模板值做同样的事情?例如:
template<int I = x>
int bar(const int x)
{
return (I);
}
这显然行不通(因为在声明之前需要 x
),但可能有一些 C++17 技巧允许这样做吗?
我想用它来设置常量表达式函数参数。
你想要的只能通过(滥用)使用类型推导来进行整数推导来完成。观察:
template<int x>
struct integer_value {};
template<int x>
void test(integer_value<x> val)
{
//x can be used here.
}
当然,您必须使用 test(integer_value<4>{})
或类似的东西调用它。
template<auto x>
using constant = std::integral_constant< std::decay_t<decltype(x)>, x >;
模板
using constant = std::integral_constant< std::decay_t<decltype(x)>, x >;
constexpr int digit_val( char c ) {
if (c >= '0' && c <='9')
return c-'0';
else if (c >= 'A' && c <= 'Z')
return c-'A'+10;
else if (c >= 'a' && c <= 'z')
return c-'a'+10;
else
throw nullptr;
}
constexpr long long ce_pow( int base, int count, long long acc=1 ){
if (!count) return acc;
return ce_pow( base, count-1, acc*(long long)base );
}
constexpr long long from_digits( long long acc, int base ){
return acc;
}
template<int I, int...Is>
constexpr long long from_digits( long long acc, int base, constant<I>, constant<Is>... ) {
return from_digits( acc+ce_pow(base, sizeof...(Is))*(long long)I, base, constant<Is>{}... );
}
template<char...cs>
constexpr long long val( constant<'0'>, constant<'x'>, constant<cs>... ){
return from_digits( 0, 16, constant<digit_val(cs)>{}... );
}
template<char...cs>
constexpr long long val( constant<'0'>, constant<'b'>, constant<cs>... ){
return from_digits( 0, 2, constant<digit_val(cs)>{}... );
}
template<char...cs>
constexpr long long val( constant<'0'>, constant<cs>... ){
return from_digits( 0, 8, constant<digit_val(cs)>{}... );
}
template<char...cs>
constexpr auto operator""_k(){
return constant< val( constant<cs>{}... ) >{};
}
之类的。现在:
template<int I>
int bar(constant<I>)
{
return (I);
}
应该与 bar(5_k);
一起工作。我可能有一些错别字,花哨的 auto
constant
模板可能会阻止推导,并且缺少 0X
和 0B
支持。但除此之外还不错。
基于替代循环的实现:
struct number_format {
int prefix = 0;
int base = 0;
};
template<char...cs>
constexpr number_format get_format( constant<'0'>, constant<'x'>, constant<cs>... ) {
return {2,16};
}
template<char...cs>
constexpr number_format get_format( constant<'0'>, constant<'X'>, constant<cs>... ) {
return {2,16};
}
template<char...cs>
constexpr number_format get_format( constant<'0'>, constant<'b'>, constant<cs>... ) {
return {2,2};
}
template<char...cs>
constexpr number_format get_format( constant<'0'>, constant<'B'>, constant<cs>... ) {
return {2,2};
}
template<char...cs>
constexpr number_format get_format( constant<'0'>, constant<cs>... ) {
return {1,8};
}
template<char...cs>
constexpr number_format get_format( constant<cs>... ) {
return {0,10};
}
template<char...Cs>
constexpr long long val( constant<Cs>...cs ){
char buff[] = {Cs...};
constexpr number_format fmt = get_format( cs... );
long long r = 0;
for (auto it = std::begin(buff)+fmt.prefix; it != std::end(buff); ++it) {
r *= fmt.base;
r += digit_val(*it);
}
return r;
}
template<char...cs>
constexpr auto operator""_k(){
return constant< val( constant<cs>{}... ) >{};
}
是否可以推导出 c++17 函数的模板值(不是类型)?
函数 foo:
template<int I>
int foo()
{
return (I);
}
可以通过以下方式调用:
foo<5>();
并且会 return 5.
模板类型可以通过函数参数的类型推导出来。是否有可能以某种方式对模板值做同样的事情?例如:
template<int I = x>
int bar(const int x)
{
return (I);
}
这显然行不通(因为在声明之前需要 x
),但可能有一些 C++17 技巧允许这样做吗?
我想用它来设置常量表达式函数参数。
你想要的只能通过(滥用)使用类型推导来进行整数推导来完成。观察:
template<int x>
struct integer_value {};
template<int x>
void test(integer_value<x> val)
{
//x can be used here.
}
当然,您必须使用 test(integer_value<4>{})
或类似的东西调用它。
template<auto x>
using constant = std::integral_constant< std::decay_t<decltype(x)>, x >;
模板
using constant = std::integral_constant< std::decay_t<decltype(x)>, x >;
constexpr int digit_val( char c ) {
if (c >= '0' && c <='9')
return c-'0';
else if (c >= 'A' && c <= 'Z')
return c-'A'+10;
else if (c >= 'a' && c <= 'z')
return c-'a'+10;
else
throw nullptr;
}
constexpr long long ce_pow( int base, int count, long long acc=1 ){
if (!count) return acc;
return ce_pow( base, count-1, acc*(long long)base );
}
constexpr long long from_digits( long long acc, int base ){
return acc;
}
template<int I, int...Is>
constexpr long long from_digits( long long acc, int base, constant<I>, constant<Is>... ) {
return from_digits( acc+ce_pow(base, sizeof...(Is))*(long long)I, base, constant<Is>{}... );
}
template<char...cs>
constexpr long long val( constant<'0'>, constant<'x'>, constant<cs>... ){
return from_digits( 0, 16, constant<digit_val(cs)>{}... );
}
template<char...cs>
constexpr long long val( constant<'0'>, constant<'b'>, constant<cs>... ){
return from_digits( 0, 2, constant<digit_val(cs)>{}... );
}
template<char...cs>
constexpr long long val( constant<'0'>, constant<cs>... ){
return from_digits( 0, 8, constant<digit_val(cs)>{}... );
}
template<char...cs>
constexpr auto operator""_k(){
return constant< val( constant<cs>{}... ) >{};
}
之类的。现在:
template<int I>
int bar(constant<I>)
{
return (I);
}
应该与 bar(5_k);
一起工作。我可能有一些错别字,花哨的 auto
constant
模板可能会阻止推导,并且缺少 0X
和 0B
支持。但除此之外还不错。
基于替代循环的实现:
struct number_format {
int prefix = 0;
int base = 0;
};
template<char...cs>
constexpr number_format get_format( constant<'0'>, constant<'x'>, constant<cs>... ) {
return {2,16};
}
template<char...cs>
constexpr number_format get_format( constant<'0'>, constant<'X'>, constant<cs>... ) {
return {2,16};
}
template<char...cs>
constexpr number_format get_format( constant<'0'>, constant<'b'>, constant<cs>... ) {
return {2,2};
}
template<char...cs>
constexpr number_format get_format( constant<'0'>, constant<'B'>, constant<cs>... ) {
return {2,2};
}
template<char...cs>
constexpr number_format get_format( constant<'0'>, constant<cs>... ) {
return {1,8};
}
template<char...cs>
constexpr number_format get_format( constant<cs>... ) {
return {0,10};
}
template<char...Cs>
constexpr long long val( constant<Cs>...cs ){
char buff[] = {Cs...};
constexpr number_format fmt = get_format( cs... );
long long r = 0;
for (auto it = std::begin(buff)+fmt.prefix; it != std::end(buff); ++it) {
r *= fmt.base;
r += digit_val(*it);
}
return r;
}
template<char...cs>
constexpr auto operator""_k(){
return constant< val( constant<cs>{}... ) >{};
}