Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在运行时获取模板元编程编译时常量 背景_C++_Templates_Runtime_Metaprogramming - Fatal编程技术网

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 }