C++ 带有参数列表初始化的模板参数推断
我一直在尝试创建一个类,它表示数组的非拥有多维视图(有点像N维C++ 带有参数列表初始化的模板参数推断,c++,templates,c++17,template-argument-deduction,C++,Templates,C++17,Template Argument Deduction,我一直在尝试创建一个类,它表示数组的非拥有多维视图(有点像N维std::string\u视图),其中维度是“动态”变化的。即维度的数量和维度大小不与类绑定,而是在访问元素时指定(通过操作符())。以下代码总结了我正在寻找的功能: #include <array> #include <cstddef> template<typename T> struct array_view { T* _data; // Use of std::arra
std::string\u视图),其中维度是“动态”变化的。即维度的数量和维度大小不与类绑定,而是在访问元素时指定(通过操作符()
)。以下代码总结了我正在寻找的功能:
#include <array>
#include <cstddef>
template<typename T>
struct array_view {
T* _data;
// Use of std::array here is not specific, I intend to use my own, but similar in functionality, indices class.
template<std::size_t N>
T& operator()(std::array<std::size_t, N> dimensions, std::array<std::size_t, N> indices) const
{
std::size_t offset = /* compute the simple offset */;
return _data[offset];
}
};
int main()
{
int arr[3 * 4 * 5] = {0};
array_view<int> view{arr};
/* Access element 0. */
// Should call array_view<int>::operator()<3>(std::array<std::size_t, 3>, std::array<std::size_t, 3>)
view({5, 4, 3}, {0, 0, 0}) = 1;
}
我不是模板实例化/演绎方面的专家。然而,在我看来,编译器试图从std::initializer\u list
参数中推断N
,这失败了,因为operator()
被声明为采用std::array
参数。因此编译失败
这样做,显示出类似的结果:
template<typename T>
struct foo {
T val;
};
struct bar {
template<typename T>
void operator()(foo<T>) {}
};
int main()
{
bar b;
b({1});
}
模板
结构foo{
T值;
};
结构条{
模板
void运算符()(foo){}
};
int main()
{
b栏;
b({1});
}
输出:
main.cpp: In function 'int main()':
main.cpp:14:7: error: no match for call to '(bar) (<brace-enclosed initializer list>)'
b({1});
^
main.cpp:8:10: note: candidate: 'template<class T> void bar::operator()(foo<T>)'
void operator()(foo<T>) {}
^~~~~~~~
main.cpp:8:10: note: template argument deduction/substitution failed:
main.cpp:14:7: note: couldn't deduce template parameter 'T'
b({1});
main.cpp:在函数“int main()”中:
main.cpp:14:7:错误:调用'(bar)()时不匹配
b({1});
^
main.cpp:8:10:注意:候选者:'template void bar::operator()(foo)'
void运算符()(foo){}
^~~~~~~~
main.cpp:8:10:注意:模板参数扣除/替换失败:
main.cpp:14:7:注意:无法推断模板参数“t”
b({1});
编译器似乎甚至没有尝试将{1}
(这是foo
的有效初始化)转换为foo
,因为它在推导函数模板参数失败后停止
那么,有什么方法可以实现我想要的功能吗?我是否缺少一些新的语法,或者有其他方法可以实现同样的功能,或者根本不可能实现
那么,有没有办法实现我想要的功能呢?是否有我遗漏的一些新语法,或者有一种替代方法可以做到这一点,或者根本不可能做到
显然,您可以按如下方式显式显示N
值
view.operator()<3U>({{5U, 4U, 3U}}, {{0U, 0U, 0U}}) = 1;
view({{5U, 4U, 3U}}, 0U, 0U, 0U) = 1;
显然,在操作符内部使用索引
,可能会更复杂,并且可能需要添加一些关于Ts.
类型的检查(以验证所有索引都可转换为std::size\u t
但是我想您也可以将func()
方法定义为原始的操作符()
下面是一个完整的工作示例
#include <array>
#include <cstddef>
template <typename T>
struct array_view
{
T * _data;
template <std::size_t N>
T & func (std::array<std::size_t, N> const & dims,
std::array<std::size_t, N> const & inds) const
{
std::size_t offset = 0 /* compute the simple offset */;
return _data[offset];
}
template <typename ... Ts>
T & operator() (std::array<std::size_t, sizeof...(Ts)> const & dims,
Ts const & ... indices) const
{ return func(dims, {{ indices... }}); }
};
int main ()
{
int arr[3 * 4 * 5] = {0};
array_view<int> view{arr};
view({{5U, 4U, 3U}}, 0U, 0U, 0U) = 1;
}
#包括
#包括
模板
结构数组视图
{
T*_数据;
模板
T&func(标准::数组常量和dims,
std::数组常量和inds)常量
{
std::size_t offset=0/*计算简单偏移量*/;
返回_数据[偏移];
}
模板
T运算符()(标准::数组常量和dims,
Ts常数和…索引)常数
{return func(dims,{{index…}});}
};
int main()
{
int arr[3*4*5]={0};
数组_视图{arr};
视图({5U,4U,3U},0U,0U,0U)=1;
}
它无法编译的原因是{5,4,3}
和{0,0,0}
(称为带括号的init列表)与一级表达式不同。它们没有类型。在模板推导中,我们尝试将类型与表达式匹配,但我们无法针对大括号的init列表进行匹配。即使可以,大括号的init列表也不是任何类型的std::array
,因此不匹配。这是我们需要额外语言支持的我们只是没有
有两个例外
最大的一个是std::initializer\u list
。但是它具有我们在本例中不想要的运行时大小,因为您希望强制执行维度
和索引
参数具有相同的大小(大概)
另一个是原始数组。您可以从带括号的init列表推断出T[N]
。因此您可以编写如下内容:
template <typename D, typename I, std::size_t N>
T& operator()(D const (&dimensions)[N], I const (&indices)[N]) const;
模板
T&运算符()(D常数和维数)[N],I常数和索引[N])常数;
这将允许您编写视图({5,4,3},{0,0,0})
,它将D
和I
作为int
和N
作为3
。它还将正确防止视图({5,4,3},{0})
和视图({5},{0,0})
编译
您可能需要添加额外的约束,使D
和I
是整数类型。我喜欢数组的想法,因为它几乎与我想要的功能相同。但是,它迫使您使用相同的元素类型来调用它,这似乎是不必要的限制(使用我最初失败的方法,所有参数都将隐式转换为std::size\t
)。我希望有一个std::tuple
stylestd::initializer\u list
,但没有。。。(甚至不能有编译时std::initializer\u list
大小,即使标准规定底层数据存储为t const[N]
。)
template <std::size_t N>
T & func (std::array<std::size_t, N> const & dims,
std::array<std::size_t, N> const & inds) const
{
std::size_t offset = 0 /* compute the simple offset */;
return _data[offset];
}
template <typename ... Ts>
T & operator() (std::array<std::size_t, sizeof...(Ts)> const & dims,
Ts const & ... indices) const
{ return func(dims, {{ indices... }}); }
#include <array>
#include <cstddef>
template <typename T>
struct array_view
{
T * _data;
template <std::size_t N>
T & func (std::array<std::size_t, N> const & dims,
std::array<std::size_t, N> const & inds) const
{
std::size_t offset = 0 /* compute the simple offset */;
return _data[offset];
}
template <typename ... Ts>
T & operator() (std::array<std::size_t, sizeof...(Ts)> const & dims,
Ts const & ... indices) const
{ return func(dims, {{ indices... }}); }
};
int main ()
{
int arr[3 * 4 * 5] = {0};
array_view<int> view{arr};
view({{5U, 4U, 3U}}, 0U, 0U, 0U) = 1;
}
template <typename D, typename I, std::size_t N>
T& operator()(D const (&dimensions)[N], I const (&indices)[N]) const;