为什么我的可变参数模板实例化不起作用?
Why does my variadic template instantiation not work?
我在长时间中断后重新访问 C++,我想使用模板来设计 the known "map" function -- 将函数应用于集合的每个元素的模板。
尽管我的 map
没有 return 任何东西(这里不是因素),但如果传递给“map”的函数不需要,我已经设法实现了我想要的接受附加参数:
#include <iostream>
template <typename C, void fn(const typename C::value_type &)> void map(const C & c) {
for(auto i : c) {
fn(i);
}
}
struct some_container_type { /// Just some hastily put together iterable structure type
typedef int value_type;
value_type * a;
int n;
some_container_type(value_type * a, int n): a(a), n(n) { }
value_type * begin() const {
return a;
}
value_type * end() const {
return a + n;
}
};
void some_fn(const int & e) { /// A function used for testing the "map" function
std::cout << "`fn` called for " << e << std::endl;
}
int main() {
int a[] = { 5, 7, 12 };
const some_container_type sc(a, std::size(a));
map<some_container_type, some_fn>(sc);
}
但是,我希望 map
接受额外的参数来调用 fn
。我尝试编译程序的修改变体(容器类型定义未更改):
template <typename C, typename ... T, void fn(const typename C::value_type &, T ...)> void map(const C & c, T ... args) {
for(auto i : c) {
fn(i, args...);
}
}
void some_fn(const int & e, int a, float b, char c) {
std::cout << "`fn` called for " << e << std::endl;
}
int main() {
int a[] = { 5, 7, 12 };
const some_container_type sc(a, std::size(a));
map<some_container_type, int, float, char, some_fn>(sc, 1, 2.0f, '3');
}
但是gcc -std=c++20
拒绝编译包含上述变体的修改后的程序,中止:
<source>: In function 'int main()':
<source>:29:56: error: no matching function for call to 'map<some_container_type, int, float, char, some_fn>(const some_container_type&, int, int, int)'
29 | map<some_container_type, int, float, char, some_fn>(sc, 1, 2, 3);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
<source>:16:97: note: candidate: 'template<class C, class ... T, void (* fn)(const typename C::value_type&, T ...)> void map(const C&, T ...)'
16 | template <typename C, typename ... T, void fn(const typename C::value_type &, T ... args)> void map(const C & c, T ... args) {
| ^~~
<source>:16:97: note: template argument deduction/substitution failed:
<source>:29:56: error: type/value mismatch at argument 2 in template parameter list for 'template<class C, class ... T, void (* fn)(const typename C::value_type&, T ...)> void map(const C&, T ...)'
29 | map<some_container_type, int, float, char, some_fn>(sc, 1, 2, 3);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
<source>:29:56: note: expected a type, got 'some_fn'
Microsoft Visual C++ 编译器 (19.24.28314
) 给出了更具描述性的错误消息:
error C3547: template parameter 'fn' cannot be used because it follows a template parameter pack and cannot be deduced from the function parameters of 'map'
有人可以解释一下我是否以及如何按照惯用方式完成 map
接受任意参数以将这些转发给 fn
吗?
我知道我可以将 fn
作为参数传递给 map
函数 而不是将其指定为 模板的参数,但出于与内联相关的原因以及为了更好地理解 C++ 模板,我想保留 fn
一个 模板 而不是 函数 参数。
我也不想使用任何库,包括标准库(我在上面的例子中展示的 std
的用途只是为了澄清问题)。我知道库中某处有“functor”和“forward”,但我想它们也是用 C++ 编写的,所以我很好奇是否可以在没有任何库的情况下解决我的问题。
解决这个问题的一个简单方法是推断函数的非类型模板参数,然后重新排序模板参数列表
template <typename C, auto fn, typename ... T>
void map(const C & c, T ... args) {
for(auto i : c) {
fn(i, args...);
}
}
然后这样称呼它
map<some_container_type, some_fn, int, float, char>(sc, 1, 2.0f, '3');
这是一个demo
您也可以将 fn
移动到模板参数列表的开头。
template <auto fn, typename C, typename ... T>
void map(const C & c, T ... args) {
for(auto i : c) {
fn(i, args...);
}
}
现在由于 C
和 T
可以从函数参数中推导出来,这使得调用站点更清晰
map<some_fn>(sc, 1, 2.0f, '3');
这是一个demo
我在长时间中断后重新访问 C++,我想使用模板来设计 the known "map" function -- 将函数应用于集合的每个元素的模板。
尽管我的 map
没有 return 任何东西(这里不是因素),但如果传递给“map”的函数不需要,我已经设法实现了我想要的接受附加参数:
#include <iostream>
template <typename C, void fn(const typename C::value_type &)> void map(const C & c) {
for(auto i : c) {
fn(i);
}
}
struct some_container_type { /// Just some hastily put together iterable structure type
typedef int value_type;
value_type * a;
int n;
some_container_type(value_type * a, int n): a(a), n(n) { }
value_type * begin() const {
return a;
}
value_type * end() const {
return a + n;
}
};
void some_fn(const int & e) { /// A function used for testing the "map" function
std::cout << "`fn` called for " << e << std::endl;
}
int main() {
int a[] = { 5, 7, 12 };
const some_container_type sc(a, std::size(a));
map<some_container_type, some_fn>(sc);
}
但是,我希望 map
接受额外的参数来调用 fn
。我尝试编译程序的修改变体(容器类型定义未更改):
template <typename C, typename ... T, void fn(const typename C::value_type &, T ...)> void map(const C & c, T ... args) {
for(auto i : c) {
fn(i, args...);
}
}
void some_fn(const int & e, int a, float b, char c) {
std::cout << "`fn` called for " << e << std::endl;
}
int main() {
int a[] = { 5, 7, 12 };
const some_container_type sc(a, std::size(a));
map<some_container_type, int, float, char, some_fn>(sc, 1, 2.0f, '3');
}
但是gcc -std=c++20
拒绝编译包含上述变体的修改后的程序,中止:
<source>: In function 'int main()':
<source>:29:56: error: no matching function for call to 'map<some_container_type, int, float, char, some_fn>(const some_container_type&, int, int, int)'
29 | map<some_container_type, int, float, char, some_fn>(sc, 1, 2, 3);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
<source>:16:97: note: candidate: 'template<class C, class ... T, void (* fn)(const typename C::value_type&, T ...)> void map(const C&, T ...)'
16 | template <typename C, typename ... T, void fn(const typename C::value_type &, T ... args)> void map(const C & c, T ... args) {
| ^~~
<source>:16:97: note: template argument deduction/substitution failed:
<source>:29:56: error: type/value mismatch at argument 2 in template parameter list for 'template<class C, class ... T, void (* fn)(const typename C::value_type&, T ...)> void map(const C&, T ...)'
29 | map<some_container_type, int, float, char, some_fn>(sc, 1, 2, 3);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
<source>:29:56: note: expected a type, got 'some_fn'
Microsoft Visual C++ 编译器 (19.24.28314
) 给出了更具描述性的错误消息:
error C3547: template parameter 'fn' cannot be used because it follows a template parameter pack and cannot be deduced from the function parameters of 'map'
有人可以解释一下我是否以及如何按照惯用方式完成 map
接受任意参数以将这些转发给 fn
吗?
我知道我可以将 fn
作为参数传递给 map
函数 而不是将其指定为 模板的参数,但出于与内联相关的原因以及为了更好地理解 C++ 模板,我想保留 fn
一个 模板 而不是 函数 参数。
我也不想使用任何库,包括标准库(我在上面的例子中展示的 std
的用途只是为了澄清问题)。我知道库中某处有“functor”和“forward”,但我想它们也是用 C++ 编写的,所以我很好奇是否可以在没有任何库的情况下解决我的问题。
解决这个问题的一个简单方法是推断函数的非类型模板参数,然后重新排序模板参数列表
template <typename C, auto fn, typename ... T>
void map(const C & c, T ... args) {
for(auto i : c) {
fn(i, args...);
}
}
然后这样称呼它
map<some_container_type, some_fn, int, float, char>(sc, 1, 2.0f, '3');
这是一个demo
您也可以将 fn
移动到模板参数列表的开头。
template <auto fn, typename C, typename ... T>
void map(const C & c, T ... args) {
for(auto i : c) {
fn(i, args...);
}
}
现在由于 C
和 T
可以从函数参数中推导出来,这使得调用站点更清晰
map<some_fn>(sc, 1, 2.0f, '3');
这是一个demo