C++ 强制 std::initializer_list 到模板函数中的容器
C++ coerce std::initializer_list to container in templated function
我无法将初始化列表传递给模板函数,然后调用非模板函数,该函数会将初始化列表强制转换为容器。但是,当跳过中间模板函数时,它会编译。
#include <iostream>
#include <vector>
struct MyLoader {
static auto load(const std::vector<int> &v) {
return v;
}
};
template<typename Loader, typename... Args>
auto makeVector(Args&&... args) {
return Loader::load(std::forward<Args>(args)...);
}
int main() {
auto v = makeVector<MyLoader>({ 8, 8, 8 });
for (auto x : v) {
std::cout << x << "\n";
}
}
呈现错误:
main.cpp: In instantiation of 'auto makeVector(Args&& ...) [with Loader = MyLoader; Args = {}]':
main.cpp:18:46: required from here
main.cpp:13:24: error: no matching function for call to 'MyLoader::load()'
return Loader::load(std::forward<Args>(args)...);
~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:6:17: note: candidate: 'static auto MyLoader::load(const std::vector<int>&)'
static auto load(const std::vector<int> &v) {
^~~~
main.cpp:6:17: note: candidate expects 1 argument, 0 provided
main.cpp: In function 'int main()':
main.cpp:18:46: error: too many arguments to function 'auto makeVector(Args&& ...) [with Loader = MyLoader; Args = {}]'
auto v = makeVector<MyLoader>({ 8, 8, 8 });
^
main.cpp:12:6: note: declared here
auto makeVector(Args&&... args) {
^~~~~~~~~~
main.cpp:18:10: error: 'void v' has incomplete type
auto v = makeVector<MyLoader>({ 8, 8, 8 });
^
main.cpp:20:19: error: unable to deduce 'auto&&' from 'v'
for (auto x : v) {
但是下面的编译完全没问题:
#include <iostream>
#include <vector>
struct MyLoader {
static auto load(const std::vector<int> &v) {
return v;
}
};
int main() {
auto v = MyLoader::load({ 8, 8, 8 });
for (auto x : v) {
std::cout << x << "\n";
}
}
为什么在第一个例子中初始化列表没有被强制到 MyLoader::load()
的 std::vector
参数?
问题是 {8, 8, 8}
不能推导为类型。
如果将它传递给接收 const std::vector<int>
的方法,一切顺利,因为编译器知道 {8, 8, 8}
用于初始化 std::vector<int>
。
但是,如果您将它传递给一个接收 未知类型 参数的可变参数列表 (Args&&... args
) 的函数,这将不起作用,因为编译器不会不知道 类型是 {8, 8, 8}
.
建议:以可变方式传递值
auto v = makeVector<MyLoader>(8, 8, 8);
因此编译器可以将 Args...
检测为 int, int, int
,并传递给 load()
添加图形
// ------------------V-----------------------------V
return Loader::load( { std::forward<Args>(args)... } );
如果你真的(真的!)想要将值作为初始化列表传递给 makeVector()
,你可以将它们作为数组拦截
template <typename Ldr, std::size_t Dim, typename Arg>
auto makeVector (Arg(&&arg)[Dim])
因此编译器可以推导出类型(Arg
,如 int
)和大小(Dim
,3
在 {8, 8, 8}
的情况下。
但是要解压数组你需要索引,所以需要一个函数助手。
有点像
template <typename Ldr, std::size_t ... Is, std::size_t Dim, typename Arg>
auto makeVectorH (std::index_sequence<Is...> const &, Arg(&&arg)[Dim])
{ return Ldr::load({std::forward<Arg>(arg[Is])...}); }
template <typename Ldr, std::size_t Dim, typename Arg>
auto makeVector (Arg(&&arg)[Dim])
{ return makeVectorH<Ldr>(std::make_index_sequence<Dim>{},
std::forward<Arg[Dim]>(arg)); }
以下是针对数组情况的完整编译 C++14 示例(但我建议更简单地使用可变参数)
#include <vector>
#include <utility>
#include <iostream>
struct MyLoader
{ static auto load(const std::vector<int> &v) { return v; } };
template <typename Ldr, std::size_t ... Is, std::size_t Dim, typename Arg>
auto makeVectorH (std::index_sequence<Is...> const &, Arg(&&arg)[Dim])
{ return Ldr::load({std::forward<Arg>(arg[Is])...}); }
template <typename Ldr, std::size_t Dim, typename Arg>
auto makeVector (Arg(&&arg)[Dim])
{ return makeVectorH<Ldr>(std::make_index_sequence<Dim>{},
std::forward<Arg[Dim]>(arg)); }
int main ()
{
auto v = makeVector<MyLoader>({8, 8, 8});
for (auto x : v)
std::cout << x << "\n";
}
我无法将初始化列表传递给模板函数,然后调用非模板函数,该函数会将初始化列表强制转换为容器。但是,当跳过中间模板函数时,它会编译。
#include <iostream>
#include <vector>
struct MyLoader {
static auto load(const std::vector<int> &v) {
return v;
}
};
template<typename Loader, typename... Args>
auto makeVector(Args&&... args) {
return Loader::load(std::forward<Args>(args)...);
}
int main() {
auto v = makeVector<MyLoader>({ 8, 8, 8 });
for (auto x : v) {
std::cout << x << "\n";
}
}
呈现错误:
main.cpp: In instantiation of 'auto makeVector(Args&& ...) [with Loader = MyLoader; Args = {}]':
main.cpp:18:46: required from here
main.cpp:13:24: error: no matching function for call to 'MyLoader::load()'
return Loader::load(std::forward<Args>(args)...);
~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:6:17: note: candidate: 'static auto MyLoader::load(const std::vector<int>&)'
static auto load(const std::vector<int> &v) {
^~~~
main.cpp:6:17: note: candidate expects 1 argument, 0 provided
main.cpp: In function 'int main()':
main.cpp:18:46: error: too many arguments to function 'auto makeVector(Args&& ...) [with Loader = MyLoader; Args = {}]'
auto v = makeVector<MyLoader>({ 8, 8, 8 });
^
main.cpp:12:6: note: declared here
auto makeVector(Args&&... args) {
^~~~~~~~~~
main.cpp:18:10: error: 'void v' has incomplete type
auto v = makeVector<MyLoader>({ 8, 8, 8 });
^
main.cpp:20:19: error: unable to deduce 'auto&&' from 'v'
for (auto x : v) {
但是下面的编译完全没问题:
#include <iostream>
#include <vector>
struct MyLoader {
static auto load(const std::vector<int> &v) {
return v;
}
};
int main() {
auto v = MyLoader::load({ 8, 8, 8 });
for (auto x : v) {
std::cout << x << "\n";
}
}
为什么在第一个例子中初始化列表没有被强制到 MyLoader::load()
的 std::vector
参数?
问题是 {8, 8, 8}
不能推导为类型。
如果将它传递给接收 const std::vector<int>
的方法,一切顺利,因为编译器知道 {8, 8, 8}
用于初始化 std::vector<int>
。
但是,如果您将它传递给一个接收 未知类型 参数的可变参数列表 (Args&&... args
) 的函数,这将不起作用,因为编译器不会不知道 类型是 {8, 8, 8}
.
建议:以可变方式传递值
auto v = makeVector<MyLoader>(8, 8, 8);
因此编译器可以将 Args...
检测为 int, int, int
,并传递给 load()
添加图形
// ------------------V-----------------------------V
return Loader::load( { std::forward<Args>(args)... } );
如果你真的(真的!)想要将值作为初始化列表传递给 makeVector()
,你可以将它们作为数组拦截
template <typename Ldr, std::size_t Dim, typename Arg>
auto makeVector (Arg(&&arg)[Dim])
因此编译器可以推导出类型(Arg
,如 int
)和大小(Dim
,3
在 {8, 8, 8}
的情况下。
但是要解压数组你需要索引,所以需要一个函数助手。
有点像
template <typename Ldr, std::size_t ... Is, std::size_t Dim, typename Arg>
auto makeVectorH (std::index_sequence<Is...> const &, Arg(&&arg)[Dim])
{ return Ldr::load({std::forward<Arg>(arg[Is])...}); }
template <typename Ldr, std::size_t Dim, typename Arg>
auto makeVector (Arg(&&arg)[Dim])
{ return makeVectorH<Ldr>(std::make_index_sequence<Dim>{},
std::forward<Arg[Dim]>(arg)); }
以下是针对数组情况的完整编译 C++14 示例(但我建议更简单地使用可变参数)
#include <vector>
#include <utility>
#include <iostream>
struct MyLoader
{ static auto load(const std::vector<int> &v) { return v; } };
template <typename Ldr, std::size_t ... Is, std::size_t Dim, typename Arg>
auto makeVectorH (std::index_sequence<Is...> const &, Arg(&&arg)[Dim])
{ return Ldr::load({std::forward<Arg>(arg[Is])...}); }
template <typename Ldr, std::size_t Dim, typename Arg>
auto makeVector (Arg(&&arg)[Dim])
{ return makeVectorH<Ldr>(std::make_index_sequence<Dim>{},
std::forward<Arg[Dim]>(arg)); }
int main ()
{
auto v = makeVector<MyLoader>({8, 8, 8});
for (auto x : v)
std::cout << x << "\n";
}