通用Constexpr查找表C ++ 11

时间:2015-08-02 21:50:27

标签: c++ c++11 generics constexpr

我试图构建一个通用的查找表,它接受一个生成器函数并在编译时创建表。这是表和代的代码:

#ifndef CONSTEXPR_LOOKUPTABLE_H
#define CONSTEXPR_LOOKUPTABLE_H

#include <cstddef>

/* Generate a range */
template <std::size_t... Is>
struct seq{};

template <std::size_t N, std::size_t... Is>
struct gen_seq : gen_seq<N - 1, N - 1, Is...>{};

template <std::size_t... Is>
struct gen_seq<0, Is...> : seq<Is...>{};

/*
    The lookup table consisting of values to be 
    computed at compile-time
*/
template<std::size_t N, class T>
struct LookUpTable{
    std::size_t indexes[N];
    T values[N];

    static constexpr std::size_t length = N;
};

/*
   Generate the table from a generator function
*/
template <class Lambda, std::size_t... Is>
constexpr auto LookUpTableGenerator(seq<Is...>, Lambda f) ->
LookUpTable<sizeof...(Is), decltype(f(Is)...)>
{
    return {{ Is... }, { f(Is)... }};
}

template <std::size_t N, class Lambda>
constexpr auto LookUpTableGenerator(Lambda f) ->
decltype(LookUpTableGenerator(gen_seq<N>{}, f))
{
    return LookUpTableGenerator(gen_seq<N>{}, f);
}

#endif

这是主要功能:

#include <iostream>
#include <memory>
#include <vector>
#include <string>
#include "ConstExprLookupTable.h"

typedef unsigned short ushort;
typedef unsigned char byte;

/*
    There are only 10 digits (0 - 9)
*/
static constexpr ushort DIGITS = 10;
/*
   A table to prevent repeated division calculation:
        table[i][j] = (i + j) / 10;
*/
static constexpr ushort carry_table[DIGITS][DIGITS] = \
{ 
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
    {0, 0, 0, 0, 0, 0, 0, 0, 1, 1},
    {0, 0, 0, 0, 0, 0, 0, 1, 1, 1},
    {0, 0, 0, 0, 0, 0, 1, 1, 1, 1},
    {0, 0, 0, 0, 0, 1, 1, 1, 1, 1},
    {0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
    {0, 0, 0, 1, 1, 1, 1, 1, 1, 1},
    {0, 0, 1, 1, 1, 1, 1, 1, 1, 1},
    {0, 1, 1, 1, 1, 1, 1, 1, 1, 1}
};

static constexpr double myFunc(double x)
{
    return x / DIGITS;
}

int main()
{
    constexpr std::size_t length = 100;
    auto table = LookUpTableGenerator<length>(myFunc);
    for (auto v : table.values){
        std::cout << v << " ";
    }
    std::cout << "\n";
}

但是,这会产生以下编译时错误:

ConstExprLookupTable.h:33:46: error: template argument 2 is invalid
 LookUpTable<sizeof...(Is), decltype(f(Is)...)>
                                              ^
ConstExprLookupTable.h:33:46: error: template argument 2 is invalid
ConstExprLookupTable.h:33:46: error: template argument 2 is invalid
ConstExprLookupTable.h:33:46: error: template argument 2 is invalid
ConstExprLookupTable.h:33:46: error: template argument 2 is invalid
ConstExprLookupTable.h:33:46: error: template argument 2 is invalid
ConstExprLookupTable.h:33:46: error: template argument 2 is invalid
ConstExprLookupTable.h:33:46: error: template argument 2 is invalid
ConstExprLookupTable.h:33:46: error: template argument 2 is invalid
ConstExprLookupTable.h:33:1: error: invalid use of template-name ‘LookUpTable’ without an argument list
 LookUpTable<sizeof...(Is), decltype(f(Is)...)>
 ^
ConstExprLookupTable.h:33:12: error: expected initializer before ‘<’ token
 LookUpTable<sizeof...(Is), decltype(f(Is)...)>
            ^
virt.cpp: In function ‘int main()’:
virt.cpp:88:53: error: no matching function for call to ‘LookUpTableGenerator(double (&)(double))’
     auto table = LookUpTableGenerator<length>(myFunc);

我的问题是(终于!): 1)这可能吗?当我用具体类型(如class T)替换查找表的double参数时,代码编译正常。 2)我认为错误在这里:

template <class Lambda, std::size_t... Is>
    constexpr auto LookUpTableGenerator(seq<Is...>, Lambda f) ->
    LookUpTable<sizeof...(Is), decltype(f(Is)...)>
    {
        return {{ Is... }, { f(Is)... }};
    }

似乎不喜欢decltype。在这种情况下,decltype应该是什么?

1 个答案:

答案 0 :(得分:4)

有很多可以扩展包的上下文,但decltype不是其中之一。你必须把你的背包包裹在一个拉出类型的元函数中。有点简单:

template <typename T, typename... >
using first = T;

然后使用它:

template <class Lambda, std::size_t... Is>
constexpr auto LookUpTableGenerator(seq<Is...>, Lambda f) ->
LookUpTable<sizeof...(Is), first<decltype(f(Is))...>>

虽然所有Is都是相同的类型(size_t),但你可以直接使用它:

template <class Lambda, std::size_t... Is>
constexpr auto LookUpTableGenerator(seq<Is...>, Lambda f) ->
LookUpTable<sizeof...(Is), decltype(f(std::declval<size_t>()))>