可变数量 std::pair 元素的参数包扩展未按预期工作
Parameter pack extension for variable number of std::pair elements does not work as expected
我的用例:我想构建一个内容和大小在编译时声明为常量的 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
函数来简化它,该函数接受成对的参数包和 returns 具有正确大小和 key/value 类型的映射,如下所示:
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 <(no value), (no value)> for template parameter 'Values'
失败。现场示例 here.
我假设 std::pair
中的参数包作为模板参数应该创建类型为 std::pair
的参数包是错误的。我如何让它工作,或者甚至可以让它按照我想要的方式工作?
{..}
没有类型,只能推断为 initilizer_list<T>
或 T(&)[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 });
可能通过旧的 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}});
我的用例:我想构建一个内容和大小在编译时声明为常量的 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
函数来简化它,该函数接受成对的参数包和 returns 具有正确大小和 key/value 类型的映射,如下所示:
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 <(no value), (no value)> for template parameter 'Values'
失败。现场示例 here.
我假设 std::pair
中的参数包作为模板参数应该创建类型为 std::pair
的参数包是错误的。我如何让它工作,或者甚至可以让它按照我想要的方式工作?
{..}
没有类型,只能推断为 initilizer_list<T>
或 T(&)[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 });
可能通过旧的 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}});