【问题标题】:Initialize array of pointers to member functions at compile time using constexpr在编译时使用 constexpr 初始化指向成员函数的指针数组
【发布时间】:2016-04-14 07:28:50
【问题描述】:

我想编写以下代码,但收到错误“没有匹配将函数 'handler' 转换为类型 'void (struct Parser::*)()”。我使用带有选项的 g++ 5.3.1 -std=c++14

使用 -std=17 我可以使用 consreexpr T& std::array::operator[] (...) 但现在我编写了我的类数组。

这段代码有什么问题?

#include <cstddef>
template <typename T, size_t _size> struct array {
T elements[_size];
constexpr size_t size() const noexcept { return _size; }
constexpr bool empty() const noexcept { return size() == 0; }
constexpr T& operator[](size_t index) noexcept { return elements[index]; }
};

struct Parser {
template <size_t index> void handler ();
};

template<> void Parser::handler<0> () {
}

template<> void Parser::handler<1> () {
}


constexpr auto createArrayHandlers () {
    array <void (Parser::*)(), 2> ans{&Parser::handler<0>, &Parser::handler<1>};
    for (size_t i = 0; i < ans.size(); ++i) {
        ans[i] = &Parser::handler<0>; //ok 
        ans[i] = &Parser::handler<i>; //error
    }
    return ans;
}
constexpr auto table = createArrayHandlers();
int main() {
    //table[parse_cmd(read_from_socket())]();
    return 0;
}

现在我用以下代码替换了这段代码,但它在运行时执行

std::array<void (Parser::*)(), xxx> table {};
template <size_t i> size_t fillMemeberHandlerArray () {
    fillMemeberHandlerArray<i-1>();
    table[i] = &Parser::handler<i>;
    return i;
}

template<> size_t fillMemeberHandlerArray<0> () {
    table[0] = &Parser::handler<0>;
    return 0;
}
size_t const initTable = fillMemeberHandlerArray<table.size () - 1>();

【问题讨论】:

  • 模板参数应该是常量表达式,i(来自for)不是常量表达式。你可以使用std::index_sequence 来初始化你的数组。

标签: c++ metaprogramming std c++14 constexpr


【解决方案1】:
#include <utility>
#include <array>

namespace detail {
    template<std::size_t... Is>
    constexpr auto createArrayHandlers(std::index_sequence<Is...>) noexcept
     -> std::array<void(Parser::*)(), sizeof...(Is)>
    {
        return {{&Parser::handler<Is>...}};
    }
}

constexpr auto createArrayHandlers() noexcept
{
    return detail::createArrayHandlers(std::make_index_sequence<2>{});
}

constexpr auto table = createArrayHandlers();

Online Demo

由于这不使用容器的operator[] 来填充它,因此可以很好地使用std::array&lt;&gt; 而不是自己滚动近似值。

【讨论】:

    【解决方案2】:

    模板参数应该是常量表达式,i(来自for)不是常量表达式。

    你可以这样做

    constexpr array<void (Parser::*)(), 2> createArrayHandlers () {
         return {{&Parser::handler<0>, &Parser::handler<1>}};
    }
    

    或使用std::index_sequence 处理多个编译时间值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-04-07
      • 1970-01-01
      • 1970-01-01
      • 2010-10-11
      • 2012-11-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多