有没有办法在 C++17 中折叠初始化列表
Is there a way to fold an initializer list in C++17
有什么方法可以折叠初始值设定项列表而不是使用参数包吗?我的问题是我有一个重载的构造函数,我想根据是否使用 {}
来调用不同的构造函数。这似乎适用于初始化列表,当我使用 {}
时它设法隐藏我的另一个参数构造函数,而不是当我只使用 ()
构造它时,但如果我使用参数包则失败这并没有隐藏我的另一个参数构造函数。
另外,我看到人们在他们的折叠表达式中附加了 void ,当我提到 cppreference 时我无法理解,它似乎也没有对我的程序产生任何影响。
编辑:
应要求,举例说明问题:
#include <iostream>
#define USE_PARAMETER_PACK false
template<typename T>
struct Mega
{
int d;
T* arr;
Mega(int d) : d(d), arr(new T[d]) {}
Mega(int d, T u) : d(d), arr(new T[d])
{
std::fill(arr, arr + d, static_cast<T>(u));
}
#if USE_PARAMETER_PACK == true
template<typename ...Ts>
Mega(Ts&& ... vals) : d(sizeof...(Ts)), arr(new T[sizeof...(Ts)])
{
// fills the array with the arguments at compile time
int i = 0;
(void(arr[i++] = static_cast<T>(vals)), ...);
}
#else
template<typename U>
Mega(const std::initializer_list<U>& list) : d(list.size()), arr(new T[d])
{
auto it = list.begin();
//int i = 0;
//((arr[i++] = (list)), ...);
for (size_t i = 0; i < d; ++i, ++it)
arr[i] = static_cast<T>(*it);
}
#endif
};
template<typename T>
std::ostream& operator<<(std::ostream& os, const Mega<T>& m)
{
for (size_t i = 0; i < m.d; ++i)
os << m.arr[i] << "\t";
return os;
}
int main()
{
int* k;
k = new int[2];
k[0] = 2;
k[1] = 3;
Mega<int> l( k[0] );
// hides 1 argument ctor through {} invocation if using initializer_list,
// not so with parameter pack
Mega<int> m({ k[0]});
Mega<int> n(k[0], k[1]);
// hides 2 argument ctor through {} invocation if using initializer list
// not so with parameter pack
Mega<int> o({ k[0], k[1] });
std::cout << l << "\n";
std::cout << m << "\n";
std::cout << n << "\n";
std::cout << o << "\n";
return 0;
}
注意注释掉的部分,我希望能够做这样的事情,以便在编译时计算出已知大小参数列表的填充过程,而不是我使用 for环形。
应该为第一个 cout 打印出一些垃圾值,为第二个打印出 2(至少在 MSVC2017 中是这样,不知道这种隐藏机制是否符合标准)。请注意,如果将 define 设置为 true,则可以使用参数包 ctor,但即使使用 {}
语法也无法隐藏单参数 ctor。
Edit2:为了最大的方便进一步更新了代码,只需将 define 更改为 true 即可看到参数包无法使用 {}
语法隐藏 1 和 2 参数构造函数,而初始化列表ctor 设法做到了。
链接:
使用初始化列表:
http://coliru.stacked-crooked.com/a/7b876e1dfbb18d73
输出:
0 0
2
3 3
2 3
使用参数包:
http://coliru.stacked-crooked.com/a/11042b2fc45b5259
输出:
0 0
0 0
3 3
3 3
因为 initializer_list
的长度在编译时未知(特别是,具有不同数量元素的不同调用点调用相同的函数),它是不可能对其进行任何constexpr
处理。 (相关的成员函数 are constexpr
,但你不能在函数参数上使用它们。)折叠表达式特别需要一个参数包,其大小始终是一个常量表达式。
有什么方法可以折叠初始值设定项列表而不是使用参数包吗?我的问题是我有一个重载的构造函数,我想根据是否使用 {}
来调用不同的构造函数。这似乎适用于初始化列表,当我使用 {}
时它设法隐藏我的另一个参数构造函数,而不是当我只使用 ()
构造它时,但如果我使用参数包则失败这并没有隐藏我的另一个参数构造函数。
另外,我看到人们在他们的折叠表达式中附加了 void ,当我提到 cppreference 时我无法理解,它似乎也没有对我的程序产生任何影响。
编辑: 应要求,举例说明问题:
#include <iostream>
#define USE_PARAMETER_PACK false
template<typename T>
struct Mega
{
int d;
T* arr;
Mega(int d) : d(d), arr(new T[d]) {}
Mega(int d, T u) : d(d), arr(new T[d])
{
std::fill(arr, arr + d, static_cast<T>(u));
}
#if USE_PARAMETER_PACK == true
template<typename ...Ts>
Mega(Ts&& ... vals) : d(sizeof...(Ts)), arr(new T[sizeof...(Ts)])
{
// fills the array with the arguments at compile time
int i = 0;
(void(arr[i++] = static_cast<T>(vals)), ...);
}
#else
template<typename U>
Mega(const std::initializer_list<U>& list) : d(list.size()), arr(new T[d])
{
auto it = list.begin();
//int i = 0;
//((arr[i++] = (list)), ...);
for (size_t i = 0; i < d; ++i, ++it)
arr[i] = static_cast<T>(*it);
}
#endif
};
template<typename T>
std::ostream& operator<<(std::ostream& os, const Mega<T>& m)
{
for (size_t i = 0; i < m.d; ++i)
os << m.arr[i] << "\t";
return os;
}
int main()
{
int* k;
k = new int[2];
k[0] = 2;
k[1] = 3;
Mega<int> l( k[0] );
// hides 1 argument ctor through {} invocation if using initializer_list,
// not so with parameter pack
Mega<int> m({ k[0]});
Mega<int> n(k[0], k[1]);
// hides 2 argument ctor through {} invocation if using initializer list
// not so with parameter pack
Mega<int> o({ k[0], k[1] });
std::cout << l << "\n";
std::cout << m << "\n";
std::cout << n << "\n";
std::cout << o << "\n";
return 0;
}
注意注释掉的部分,我希望能够做这样的事情,以便在编译时计算出已知大小参数列表的填充过程,而不是我使用 for环形。
应该为第一个 cout 打印出一些垃圾值,为第二个打印出 2(至少在 MSVC2017 中是这样,不知道这种隐藏机制是否符合标准)。请注意,如果将 define 设置为 true,则可以使用参数包 ctor,但即使使用 {}
语法也无法隐藏单参数 ctor。
Edit2:为了最大的方便进一步更新了代码,只需将 define 更改为 true 即可看到参数包无法使用 {}
语法隐藏 1 和 2 参数构造函数,而初始化列表ctor 设法做到了。
链接: 使用初始化列表: http://coliru.stacked-crooked.com/a/7b876e1dfbb18d73 输出:
0 0
2
3 3
2 3
使用参数包: http://coliru.stacked-crooked.com/a/11042b2fc45b5259 输出:
0 0
0 0
3 3
3 3
因为 initializer_list
的长度在编译时未知(特别是,具有不同数量元素的不同调用点调用相同的函数),它是不可能对其进行任何constexpr
处理。 (相关的成员函数 are constexpr
,但你不能在函数参数上使用它们。)折叠表达式特别需要一个参数包,其大小始终是一个常量表达式。