【问题标题】:Parameter pack extension for variable number of std::pair elements does not work as expected可变数量的 std::pair 元素的参数包扩展无法按预期工作
【发布时间】:2021-02-11 13:25:32
【问题描述】:

我的用例:我想构建一个常量内容和大小在编译时声明的 constexpr 映射。我正在使用 C++ 14。这是我目前对该容器的基本方法:

template <typename KeyType, typename ValueType, size_t size>
struct ConstantMap
{
    using PairType = std::pair<KeyType, ValueType>;

    using StorageType = std::array<PairType, size>;

    const StorageType storage;

    constexpr ValueType at (const KeyType& key) const
    {
        const auto it = std::find_if (storage.begin(), storage.end(), [&key] (const auto& v) { return v.first == key; });

        if (it != storage.end())
            return it.second;

        throw std::range_error ("ConstantMap: Key not found");
    }

    constexpr ValueType operator[] (const KeyType& key) const { return at (key); }
};

有效的方法是像这样初始化它:

constexpr std::array<std::pair<int, int>, 2> values =
{{
    { 1, 2 },
    { 3, 4 }
}};

constexpr ConstantMap<int, int, 2> myMap {{ values }};

我想通过一个 makeConstantMap 函数来简化这一点,该函数接受一个成对的参数包并返回一个具有正确大小和键/值类型的映射,如下所示:

constexpr auto myMap = makeConstantMap<int, int> ({ 1, 2 }, { 3, 4 });

我的做法是

template <typename KeyType, typename ValueType, typename... Values>
constexpr ConstantMap<KeyType, ValueType, sizeof...(Values)> makeConstantMap (std::pair<KeyType, Values>&&... pairs)
{
    return {{ std::forward<std::pair<KeyType, Values>> (pairs)... }};
}

candidate template ignored: substitution failure [with KeyType = int, ValueType = int]: deduced incomplete pack &lt;(no value), (no value)&gt; for template parameter 'Values' 失败。现场示例here

似乎我假设std::pair 中的参数包作为模板参数应该创建一个类型为std::pair 的参数包是错误的。我如何让它工作,或者甚至可以让它按照我想要的方式工作?

【问题讨论】:

  • 不是问题,但std::pair&lt;KeyType, Values&gt;&amp;&amp; 没有进行转发引用。只有在需要推导整个类型时才会创建转发引用,即:template &lt;typename T&gt; void foo(T&amp;&amp; fr)

标签: c++ c++14 variadic-templates


【解决方案1】:

也许是通过一个旧的 C 风格的数组?

template <typename KT, typename VT, std::size_t Dim, std::size_t ... Is>
constexpr auto mcp_helper (std::pair<KT, VT> const (& arr)[Dim],
                           std::index_sequence<Is...>)
 { return ConstantMap<KT, VT, Dim>{{ arr[Is]... }}; }

template <typename KT, typename VT, std::size_t Dim>
constexpr auto makeConstantMap (std::pair<KT, VT> const (& arr)[Dim])
 { return mcp_helper<KT, VT>(arr, std::make_index_sequence<Dim>{}); }

// ...

auto x = makeConstantMap<int, int>({{1, 2}, {3, 4}});

【讨论】:

  • 是的,太好了。这就是我一直在寻找的答案
【解决方案2】:

{..}没有类型,只能推导出为initilizer_list&lt;T&gt;T(&amp;)[N]

所以调用必须是这样的:

makeConstantMap(std::pair<int, int>{ 1, 2 }, std::pair<int, int>{ 3, 4 });

具有硬编码限制的可能解决方法如下:

template <typename Key, typename Value>
struct MapMaker
{
    constexpr ConstantMap<Key, Value, 0> operator()() const { return {}; }
    constexpr ConstantMap<Key, Value, 1> operator()(std::pair<Key, value> p1) const {
        return {{ std::array<std::pair<Key, value>, 1>{{p1}} }};
    }

    constexpr ConstantMap<Key, Value, 2> operator()(std::pair<Key, value> p1,
                                                    std::pair<Key, value> p2) const {
        return {{ std::array<std::pair<Key, value>, 1>{{p1, p2}} }};
    }

    // ...
};

constexpr auto myMap = MapMaker<int, int>{}({ 1, 2 }, { 3, 4 });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-11
    • 2015-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-12
    • 1970-01-01
    • 2018-05-09
    相关资源
    最近更新 更多