是否可以就地构造一个固定大小的数组作为函数参数?
Is it possible to construct a fixed sized array in-place as a function argument?
这主要是一个C++语法角定长数组相关的问题。
假设我有一个利用类型信息的函数,例如:
template<class T> void fun(T const& t){
std::cout << typeid(t).name() << std::endl;
}
我可以传递一个值或一个临时对象:
int i;
fun(i); // prints "int" ("i" actually)
fun(int{}); // prints "int" ("i" actually)
但是我不能对数组做同样的事情
double a[10][10];
fun(a); // ok, prints "a[10][10]" ("A10_A10_d" actually)
fun(double[10][10]); // doesn't compile
fun(double{}[10][10]); // doesn't compile
fun(double[10][10]{}); // doesn't compile
fun(double()[10][10]); // doesn't compile
fun(double[10][10]()); // doesn't compile
fun(double(&)[10][10]); // doesn't compile
fun(double(*)[10][10]); // doesn't compile
原则上我可以这样做:
typedef double a1010[10][10];
fun(a1010{});
但是,是否可以不预定义类型定义?
是否可以就地构造一个固定大小的数组作为函数参数?
完整代码:
template<class T> void fun(T const& t){
std::cout << typeid(t).name() << std::endl;
}
typedef double a1010[10][10];
int main(){
int i;
fun(i); // prints "int" ("i" actually)
double a[10][10];
fun(a); // prints "a[10][10]" ("A10_A10_d" actually)
fun(a1010{});
fun(int{}); // prints "int"
/* fun(double[10][10]); // doesn't compile
fun(double{}[10][10]); // doesn't compile
fun(double[10][10]{}); // doesn't compile
fun(double()[10][10]); // doesn't compile
fun(double[10][10]()); // doesn't compile
fun(double(&)[10][10]); // doesn't compile
fun(double(*)[10][10]); // doesn't compile
*/
return 0;
}
奖励积分(可能是赏金):可变大小数组呢?
int N = 10;
f(double[N]);
尝试:
fun((int[3]){1,2,3});
fun((int[5]){});
至于"bonus points":可变大小的数组不是语言的一部分。此语言扩展不适用于模板参数:
prog.cc:4:6: note: candidate template ignored: substitution failure :
variably modified type 'int [n]' cannot be used as a template argument
fun(const T&t)
编辑
正如 Chris 指出的那样,上述解决方案建议使用 复合文字,这是对 C++ 的扩展。有一个解决方案可以避免这种对 C++ 的扩展,使用一个简单的助手 class:
template <class T, std::size_t N>
struct my_array
{
T data[N];
};
template <class T, std::size_t N>
void print(const T (&x)[N])
{
for (auto i: x)
std::cout << i << '\n';
}
int main()
{
print(my_array<int,3>{9,10,11}.data);
}
这很好用,但需要将模板参数添加到 my_array,这不是推导出来的。使用 C++17 可以自动推断类型和大小:
template <class T, std::size_t N>
struct my_array
{
constexpr my_array(std::initializer_list<T> x)
{
std::size_t i = 0;
for (auto val : x)
data[i++] = val;
}
T data[N];
};
template <class ...T>
my_array(T...) -> my_array<typename std::common_type<T...>::type, sizeof...(T)>;
int main()
{
print(my_array{9,10,11}.data);
}
对于二维数组,这稍微复杂一些:
template <class T, std::size_t N1, std::size_t N2>
struct my_array2d
{
constexpr my_array2d(std::initializer_list<std::initializer_list<T> > x)
{
std::size_t i = 0;
for (const auto & row : x) {
int j=0;
for (const auto & val: row) {
data[i][j++] = val;
}
i++;
}
}
T data[N1][N2];
};
int main()
{
work(my_array2d<int, 3, 2>{{9,1},{10,2},{11,3}}.data);
}
我已经放弃了二维数组的推导指南,但我相信它们是可能的。
您已经尝试了很多与 double
的组合,但您似乎错过了一个。
fun((double[10][10]){});
编译并给出:A10_A10_d
这主要是一个C++语法角定长数组相关的问题。
假设我有一个利用类型信息的函数,例如:
template<class T> void fun(T const& t){
std::cout << typeid(t).name() << std::endl;
}
我可以传递一个值或一个临时对象:
int i;
fun(i); // prints "int" ("i" actually)
fun(int{}); // prints "int" ("i" actually)
但是我不能对数组做同样的事情
double a[10][10];
fun(a); // ok, prints "a[10][10]" ("A10_A10_d" actually)
fun(double[10][10]); // doesn't compile
fun(double{}[10][10]); // doesn't compile
fun(double[10][10]{}); // doesn't compile
fun(double()[10][10]); // doesn't compile
fun(double[10][10]()); // doesn't compile
fun(double(&)[10][10]); // doesn't compile
fun(double(*)[10][10]); // doesn't compile
原则上我可以这样做:
typedef double a1010[10][10];
fun(a1010{});
但是,是否可以不预定义类型定义?
是否可以就地构造一个固定大小的数组作为函数参数?
完整代码:
template<class T> void fun(T const& t){
std::cout << typeid(t).name() << std::endl;
}
typedef double a1010[10][10];
int main(){
int i;
fun(i); // prints "int" ("i" actually)
double a[10][10];
fun(a); // prints "a[10][10]" ("A10_A10_d" actually)
fun(a1010{});
fun(int{}); // prints "int"
/* fun(double[10][10]); // doesn't compile
fun(double{}[10][10]); // doesn't compile
fun(double[10][10]{}); // doesn't compile
fun(double()[10][10]); // doesn't compile
fun(double[10][10]()); // doesn't compile
fun(double(&)[10][10]); // doesn't compile
fun(double(*)[10][10]); // doesn't compile
*/
return 0;
}
奖励积分(可能是赏金):可变大小数组呢?
int N = 10;
f(double[N]);
尝试:
fun((int[3]){1,2,3});
fun((int[5]){});
至于"bonus points":可变大小的数组不是语言的一部分。此语言扩展不适用于模板参数:
prog.cc:4:6: note: candidate template ignored: substitution failure : variably modified type 'int [n]' cannot be used as a template argument fun(const T&t)
编辑
正如 Chris 指出的那样,上述解决方案建议使用 复合文字,这是对 C++ 的扩展。有一个解决方案可以避免这种对 C++ 的扩展,使用一个简单的助手 class:
template <class T, std::size_t N>
struct my_array
{
T data[N];
};
template <class T, std::size_t N>
void print(const T (&x)[N])
{
for (auto i: x)
std::cout << i << '\n';
}
int main()
{
print(my_array<int,3>{9,10,11}.data);
}
这很好用,但需要将模板参数添加到 my_array,这不是推导出来的。使用 C++17 可以自动推断类型和大小:
template <class T, std::size_t N>
struct my_array
{
constexpr my_array(std::initializer_list<T> x)
{
std::size_t i = 0;
for (auto val : x)
data[i++] = val;
}
T data[N];
};
template <class ...T>
my_array(T...) -> my_array<typename std::common_type<T...>::type, sizeof...(T)>;
int main()
{
print(my_array{9,10,11}.data);
}
对于二维数组,这稍微复杂一些:
template <class T, std::size_t N1, std::size_t N2>
struct my_array2d
{
constexpr my_array2d(std::initializer_list<std::initializer_list<T> > x)
{
std::size_t i = 0;
for (const auto & row : x) {
int j=0;
for (const auto & val: row) {
data[i][j++] = val;
}
i++;
}
}
T data[N1][N2];
};
int main()
{
work(my_array2d<int, 3, 2>{{9,1},{10,2},{11,3}}.data);
}
我已经放弃了二维数组的推导指南,但我相信它们是可能的。
您已经尝试了很多与 double
的组合,但您似乎错过了一个。
fun((double[10][10]){});
编译并给出:A10_A10_d