C++ 在运行时获取模板元编程编译时常量 背景
考虑以下几点:C++ 在运行时获取模板元编程编译时常量 背景,c++,templates,runtime,metaprogramming,C++,Templates,Runtime,Metaprogramming,考虑以下几点: template <unsigned N> struct Fibonacci { enum { value = Fibonacci<N-1>::value + Fibonacci<N-2>::value }; }; template <> struct Fibonacci<1> { enum { value = 1 }; }; templ
template <unsigned N>
struct Fibonacci
{
enum
{
value = Fibonacci<N-1>::value + Fibonacci<N-2>::value
};
};
template <>
struct Fibonacci<1>
{
enum
{
value = 1
};
};
template <>
struct Fibonacci<0>
{
enum
{
value = 0
};
};
模板
结构斐波那契
{
枚举
{
value=Fibonacci::value+Fibonacci::value
};
};
模板
结构斐波那契
{
枚举
{
值=1
};
};
模板
结构斐波那契
{
枚举
{
值=0
};
};
这是一个常见的示例,我们可以将斐波那契数的值作为编译时常量:
int main(void)
{
std::cout << "Fibonacci(15) = ";
std::cout << Fibonacci<15>::value;
std::cout << std::endl;
}
int main(无效)
{
std::cout模板
结构斐波那契
{
枚举
{
value=Fibonacci::value+Fibonacci::value
};
静态无效添加_值(向量和v)
{
斐波那契:加上_值(v);
v、 推回(值);
}
};
模板
结构斐波那契
{
枚举
{
值=0
};
静态无效添加_值(向量和v)
{
v、 推回(值);
}
};
模板
结构斐波那契
{
枚举
{
值=1
};
静态无效添加_值(向量和v)
{
斐波那契:加上_值(v);
v、 推回(值);
}
};
int main()
{
向量斐波那契;
斐波那契::添加_值(斐波那契顺序);
对于(inti=0;i,C(大部分是C++)的一个基本概念是,你不需要为你不需要的东西付费
自动生成查找表并不是编译器需要为您做的事情,即使您需要该功能,也不是所有其他人都需要
如果您想要一个查找表,请编写一个程序来创建一个查找表,然后在程序中使用该数据
如果希望在运行时计算值,请不要使用模板元程序,只要使用常规程序计算值即可。我知道这个问题很老,但它引起了我的兴趣,我不得不尝试在运行时不填充动态容器:
int main(void)
{
std::srand(static_cast<unsigned>(std::time(0)));
// ensure the table exists up to a certain size
// (even though the rest of the code won't work)
static const unsigned fibbMax = 20;
Fibonacci<fibbMax>::value;
// get index into sequence
unsigned fibb = std::rand() % fibbMax;
std::cout << "Fibonacci(" << fibb << ") = ";
std::cout << Fibonacci<fibb>::value;
std::cout << std::endl;
}
#ifndef _FIBONACCI_HPP
#define _FIBONACCI_HPP
template <unsigned long N>
struct Fibonacci
{
static const unsigned long long value = Fibonacci<N-1>::value + Fibonacci<N-2>::value;
static unsigned long long get_value(unsigned long n)
{
switch (n) {
case N:
return value;
default:
return n < N ? Fibonacci<N-1>::get_value(n)
: get_value(n-2) + get_value(n-1);
}
}
};
template <>
struct Fibonacci<0>
{
static const unsigned long long value = 0;
static unsigned long long get_value(unsigned long n)
{
return value;
}
};
template <>
struct Fibonacci<1>
{
static const unsigned long long value = 1;
static unsigned long get_value(unsigned long n)
{
return value;
}
};
#endif
\ifndef\u FIBONACCI\u水电站
#定义FIBONACCI水电站
模板
结构斐波那契
{
静态常量无符号长值=斐波那契::值+斐波那契::值;
静态无符号长get_值(无符号长n)
{
开关(n){
案例N:
返回值;
违约:
返回n
这似乎是可行的,当使用优化进行编译时(不确定是否允许),调用堆栈不会深入-堆栈上当然有正常的运行时递归,用于值(参数)n>n,其中n是模板实例化中使用的表大小。但是,一旦低于表大小,生成的代码将替换编译时计算的常量,或者最坏的情况是通过跳转表“计算”的值(在gcc中使用-c-g-Wa,-adhlns=main.s编译并检查列表),这与我认为显式switch语句将导致的结果相同
这样使用时:
int main()
{
std::cout << "F" << 39 << " is " << Fibonacci<40>::get_value(39) << '\n';
std::cout << "F" << 45 << " is " << Fibonacci<40>::get_value(45) << '\n';
}
intmain()
{
STD::CUT< P>如果你有支持可变模板(C++ 0x标准)的C++编译器,你可以在编译时将FiBOACII序列保存在元组中。在运行时,可以通过索引访问元组中的任何元素。
#include <tuple>
#include <iostream>
template<int N>
struct Fib
{
enum { value = Fib<N-1>::value + Fib<N-2>::value };
};
template<>
struct Fib<1>
{
enum { value = 1 };
};
template<>
struct Fib<0>
{
enum { value = 0 };
};
// ----------------------
template<int N, typename Tuple, typename ... Types>
struct make_fibtuple_impl;
template<int N, typename ... Types>
struct make_fibtuple_impl<N, std::tuple<Types...> >
{
typedef typename make_fibtuple_impl<N-1, std::tuple<Fib<N>, Types... > >::type type;
};
template<typename ... Types>
struct make_fibtuple_impl<0, std::tuple<Types...> >
{
typedef std::tuple<Fib<0>, Types... > type;
};
template<int N>
struct make_fibtuple : make_fibtuple_impl<N, std::tuple<> >
{};
int main()
{
auto tup = typename make_fibtuple<25>::type();
std::cout << std::get<20>(tup).value;
std::cout << std::endl;
return 0;
}
#包括
#包括
模板
结构纤维
{
枚举{value=Fib::value+Fib::value};
};
模板
结构纤维
{
枚举{值=1};
};
模板
结构纤维
{
枚举{value=0};
};
// ----------------------
模板
结构使fibtuple实现;
模板
结构make\u fibtuple\u impl
{
typedef typename make_fibtuple_impl::type type;
};
模板
结构make\u fibtuple\u impl
{
typedef std::元组类型;
};
模板
结构make\u fibtuple:make\u fibtuple\u impl
{};
int main()
{
auto tup=typename make_fibtuple::type();
std::cout您可以使用预处理器元编程技术生成交换机或静态数组。
如果复杂性不超过该方法的限制,并且您不喜欢使用生成代码或数据的额外步骤来扩展工具链,那么这是一个很好的决定。使用C++11:您可以创建一个std::array
和一个简单的getter:
名称空间详细信息
{
模板
结构Fibo:
积分常数
{
静态断言(Fibo::value+Fibo::value>=Fibo::value,
“溢出”);
};
模板结构Fibo:std::integral_常量{};
模板结构Fibo:std::integral_常量{};
模板
constexpr std::size\u t fibo(std::size\u t n,索引顺序)
{
返回常数(
std::数组{{Fibo::value…}}[n];
}
模板
constexpr std::size\u t fibo(std::size\u t n)
{
返回n
在C++14中,可以简化某些函数:
template <std::size_t ... Is>
constexpr std::size_t fibo(std::size_t n, index_sequence<Is...>)
{
constexpr std::array<std::size_t, sizeof...(Is)> fibos{{Fibo<Is>::value...}};
return fibos[n];
}
模板
constexpr std::size\u t fibo(std::size\u t n,索引顺序)
{
constexpr std::数组fibos{{Fibo::value…};
返回fibos[n];
}
我的想法是递归地将斐波那契序列保存在可变模板中,然后将其转换为数组。所有这些都是在编译时完成的。
例如,当n=5时,我们有:
F<5>::array
= F<4, 0>::array
= F<3, 0, 1>::array
= F<2, 0, 1, 1>::array
= F<1, 0, 1, 1, 2>::array
= F<0, 0, 1, 1, 2, 3>::array
= { 0, 1, 1, 2, 3 }
F::数组
=F::数组
=F::数组
=F::数组
=F::数组
=F::数组
= { 0, 1, 1, 2, 3 }
然后我们可以在运行时为数组编制索引
我的C++14实现:
#包括
#包括
#包括
模板
结构助手{static constexpr uint64_t value=Helper::value+Helper::value;};
模板
结构助手{static constexpr uint64_t value=0;};
模板
结构助手{static constexpr uint64_t value=1;};
模板
班
fibtest.exe!Fibonacci<40>::get_value(unsigned long n=41) Line 18 + 0xe bytes C++
fibtest.exe!Fibonacci<40>::get_value(unsigned long n=42) Line 18 + 0x2c bytes C++
fibtest.exe!Fibonacci<40>::get_value(unsigned long n=43) Line 18 + 0x2c bytes C++
fibtest.exe!Fibonacci<40>::get_value(unsigned long n=45) Line 18 + 0xe bytes C++
fibtest.exe!main() Line 9 + 0x7 bytes C++
fibtest.exe!__tmainCRTStartup() Line 597 + 0x17 bytes C
static unsigned long long get_value(unsigned long n)
{
switch (n) {
case N:
return value;
default:
if (n < N) {
return Fibonacci<N-1>::get_value(n);
} else {
// n > N
unsigned long long i = Fibonacci<N-1>::value, j = value, t;
for (unsigned long k = N; k < n; k++) {
t = i + j;
i = j;
j = t;
}
return j;
}
}
}
#include <tuple>
#include <iostream>
template<int N>
struct Fib
{
enum { value = Fib<N-1>::value + Fib<N-2>::value };
};
template<>
struct Fib<1>
{
enum { value = 1 };
};
template<>
struct Fib<0>
{
enum { value = 0 };
};
// ----------------------
template<int N, typename Tuple, typename ... Types>
struct make_fibtuple_impl;
template<int N, typename ... Types>
struct make_fibtuple_impl<N, std::tuple<Types...> >
{
typedef typename make_fibtuple_impl<N-1, std::tuple<Fib<N>, Types... > >::type type;
};
template<typename ... Types>
struct make_fibtuple_impl<0, std::tuple<Types...> >
{
typedef std::tuple<Fib<0>, Types... > type;
};
template<int N>
struct make_fibtuple : make_fibtuple_impl<N, std::tuple<> >
{};
int main()
{
auto tup = typename make_fibtuple<25>::type();
std::cout << std::get<20>(tup).value;
std::cout << std::endl;
return 0;
}
namespace detail
{
template <std::size_t N>
struct Fibo :
std::integral_constant<size_t, Fibo<N - 1>::value + Fibo<N - 2>::value>
{
static_assert(Fibo<N - 1>::value + Fibo<N - 2>::value >= Fibo<N - 1>::value,
"overflow");
};
template <> struct Fibo<0u> : std::integral_constant<size_t, 0u> {};
template <> struct Fibo<1u> : std::integral_constant<size_t, 1u> {};
template <std::size_t ... Is>
constexpr std::size_t fibo(std::size_t n, index_sequence<Is...>)
{
return const_cast<const std::array<std::size_t, sizeof...(Is)>&&>(
std::array<std::size_t, sizeof...(Is)>{{Fibo<Is>::value...}})[n];
}
template <std::size_t N>
constexpr std::size_t fibo(std::size_t n)
{
return n < N ?
fibo(n, make_index_sequence<N>()) :
throw std::runtime_error("out of bound");
}
} // namespace detail
constexpr std::size_t fibo(std::size_t n)
{
// 48u is the highest
return detail::fibo<48u>(n);
}
template <std::size_t ... Is>
constexpr std::size_t fibo(std::size_t n, index_sequence<Is...>)
{
constexpr std::array<std::size_t, sizeof...(Is)> fibos{{Fibo<Is>::value...}};
return fibos[n];
}
F<5>::array
= F<4, 0>::array
= F<3, 0, 1>::array
= F<2, 0, 1, 1>::array
= F<1, 0, 1, 1, 2>::array
= F<0, 0, 1, 1, 2, 3>::array
= { 0, 1, 1, 2, 3 }