我可以编写它,并且效果很好:
struct Foo
{
int i;
std::string s;
};
const Foo foo[] = {
{ 42, "the answer to the ultimate questions" },
{ 23 /*initializing only the first member, 's' gets the default value*/ }
};
我想要做的是有一个包装数组的结构,以便可以向其中添加方法:
template<typename V1, typename V2, size_t Count>
struct Map
{
std::array<std::pair<V1, V2>, Count> mappings;
//or
//std::pair<V1, V2> mappings[Count];
V1 operator()(const V2&) const;
V2 operator()(const V1&) const;
};
我想将其初始化为一个未知范围的数组,如下所示:
constexpr Map<int, std::string_view, /*???*/> = {
{ 42, "the answer to the ultimate question" },
{ 23, "some other stuff" },
{ /*...*/ }
};
但是随后出现一个问题,您需要指定一个我不想做的Count
模板参数,我希望它像在数组情况下一样工作。
我认为返回此类对象的函数可以解决问题,就像这样:
template<typename V1, typename V2, typename... Args>
constexpr auto makeMap(Args... args)
{
return Map<V1, V2, sizeof...(Args)>{ args... };
}
然后可以像这样使用它:
using Item = std::pair<int, std::string_view>;
constexpr auto map = makeMap<int, std::string_view>(
Item{ 42, "the answer to the ultimate questions" },
Item{ 23, "some other stuff" }
);
但是,如果省略Item
类型,则模板实例化将无法推断出参数类型,这会禁止我本来想要的用法:
constexpr auto map = makeMap<int, std::string_view>(
{ 42, "the answer to the ultimate questions" },
{ 23, "some other stuff" }
);
目前,我认为这是不可能的,但无论如何我想问一下。
在研究此问题的同时,我发现a proposal恰好可以实现我想要的功能。
无论如何,我很想得到任何想法。
答案 0 :(得分:5)
使用建议的to_array
:
template<typename V1, typename V2, size_t N>
constexpr auto makeMap(std::pair<V1, V2> const (&a)[N])
{
return Map<V1, V2, N>{ to_array<std::pair<V1, V2>>(a) };
}
constexpr auto map = makeMap<int, std::string_view>({
{ 42, "the answer to the ultimate question" },
{ 23, "some other stuff" },
{ /*...*/ }
});
如果编译器支持库基础TS v2,则可以在名称空间to_array
内的头文件<experimental/array>
中找到std::experimental
的实现。
答案 1 :(得分:1)
按照Jarod42的建议,我以递归的方式提出了一个递归的MakeMyMap
结构,其中有一个static
func()
,该结构接收了一系列std::pair<T1, T2>
自变量[观察:42是std::pair
参数数目的默认上限]。
template <typename T1, typename T2, std::size_t Dim>
struct MyMap
{
std::array<std::pair<T1, T2>, Dim> map;
};
template <typename T, std::size_t>
using getTheType = T;
template <typename, typename, typename = std::make_index_sequence<42u>>
struct MakeMyMap;
template <typename T1, typename T2, std::size_t ... Is>
struct MakeMyMap<T1, T2, std::index_sequence<Is...>>
: public MakeMyMap<T1, T2, std::make_index_sequence<sizeof...(Is)-1u>>
{
using MakeMyMap<T1, T2, std::make_index_sequence<sizeof...(Is)-1u>>::func;
static auto func (getTheType<std::pair<T1, T2>, Is> const & ... ps)
{ return MyMap<T1, T2, sizeof...(Is)>{ { { ps... } } }; }
};
template <typename T1, typename T2>
struct MakeMyMap<T1, T2, std::index_sequence<>>
{
static auto func ()
{ return MyMap<T1, T2, 0u>{ }; }
};
所以你可以写
auto map = MakeMyMap<int, std::string>::func(
{ 42, "the answer to the ultimate questions" },
{ 23, "some other stuff" }
);
下面是一个完整的编译示例(C ++ 14就足够了)
#include <array>
#include <string>
#include <utility>
template <typename T1, typename T2, std::size_t Dim>
struct MyMap
{
std::array<std::pair<T1, T2>, Dim> map;
};
template <typename T, std::size_t>
using getTheType = T;
template <typename, typename, typename = std::make_index_sequence<42u>>
struct MakeMyMap;
template <typename T1, typename T2, std::size_t ... Is>
struct MakeMyMap<T1, T2, std::index_sequence<Is...>>
: public MakeMyMap<T1, T2, std::make_index_sequence<sizeof...(Is)-1u>>
{
using MakeMyMap<T1, T2, std::make_index_sequence<sizeof...(Is)-1u>>::func;
static auto func (getTheType<std::pair<T1, T2>, Is> const & ... ps)
{ return MyMap<T1, T2, sizeof...(Is)>{ { { ps... } } }; }
};
template <typename T1, typename T2>
struct MakeMyMap<T1, T2, std::index_sequence<>>
{
static auto func ()
{ return MyMap<T1, T2, 0u>{ }; }
};
int main ()
{
auto map = MakeMyMap<int, std::string>::func(
{ 42, "the answer to the ultimate questions" },
{ 23, "some other stuff" }
);
static_assert( std::is_same<decltype(map),
MyMap<int, std::string, 2u>>::value, "!" );
}
使用C ++ 17,您可以使用std::string_view
而不是std::string
,可以定义constexpr
func()
函数,因此map
可以是{{ 1}}
constexpr
您还可以验证
constexpr auto map = MakeMyMap<int, std::string_view>::func(
{ 42, "the answer to the ultimate questions" },
{ 23, "some other stuff" }
);
使用新的C ++ 17变体符号 static_assert( std::is_same<decltype(map),
MyMap<int, std::string_view, 2u> const>::value, "!" );
,您可以完全避免递归using
,如下所示
MakeMyMap
其中template <typename, typename, typename = std::make_index_sequence<42u>>
struct MakeMyMap;
template <typename T1, typename T2, std::size_t ... Is>
struct MakeMyMap<T1, T2, std::index_sequence<Is...>>
: public MMM_helper<T1, T2, std::make_index_sequence<Is>>...
{ using MMM_helper<T1, T2, std::make_index_sequence<Is>>::func...; };
(“制作我的地图”助手)的定义如下
MMM_helper
以下是完整的C ++ 17(非递归)示例
template <typename, typename, typename>
struct MMM_helper;
template <typename T1, typename T2, std::size_t ... Is>
struct MMM_helper<T1, T2, std::index_sequence<Is...>>
{
static constexpr auto func (getTheType<std::pair<T1, T2>, Is> const & ... ps)
{ return MyMap<T1, T2, sizeof...(Is)>{ { { ps... } } }; }
};