问题描述
我想写一个函数,它可以接收一个ostream、一个可迭代对象v和一个函数op。该函数应该对 v 中的每个元素调用 op,然后将结果发送到 ostream。所以我写了下面的代码:
template<typename T,typename IN = decltype(*std::declval<T>().begin()),typename FT = function<ostream&(ostream&,const IN&)>
>
void func(ostream& ss,const T& v,FT op = [](ostream& os,const IN&v)->ostream&{ return os << v; }) {
for (const auto& i: v) {
std::invoke(op,ss,i);
}
}
int main() {
vector<int> vec = {1,2,3,4};
func(cout,vec);
return 0;
}
当我尝试使用 clang++ 编译这些代码时,出现以下错误。
/mnt/d/codes/stlprinter/stack.cpp:42:9: error: no matching function for call to 'invoke'
std::invoke(op,i);
^~~~~~~~~~~
/mnt/d/codes/stlprinter/stack.cpp:48:5: note: in instantiation of function template specialization 'func<std::vector<int,std::allocator<int>>,int &,std::function<std::basic_ostream<char> &(std::basic_ostream<char> &,int &)>>' requested here
func(cout,vec);
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:85:5: note: candidate template ignored: substitution failure [with _Callable = std::function<std::basic_ostream<char> &(std::basic_ostream<char> &,int &)> &,_Args = <std::basic_ostream<char> &,const int &>]: no type named 'type' in 'std::invoke_result<std::function<std::basic_ostream<char> &(std::basic_ostream<char> &,std::basic_ostream<char> &,const int &>'
invoke(_Callable&& __fn,_Args&&... __args)
^
1 error generated.
错误信息显示调用invoke时,op的类型为_Callable = std::functionstd::basic_ostream
解决方法
注意IN
,即类型decltype(*std::declval<T>().begin())
是一个引用int&
;然后对于 const IN&
,const
在引用上被限定并且被忽略。所以给定的 IN
是 int&
,const IN&
-> int& &
-> int&
。
查看 decltype
的行为:
- ...
- 如果参数是 T 类型的任何其他表达式,并且
a) ...
b) 如果表达式的值类别是左值,则 decltype 产生 T&;
c) ...
您可以通过 std::remove_reference
或 std::decay
删除引用部分。例如
template<typename T,typename IN = std::remove_reference_t<decltype(*std::declval<T>().begin())>,// ^^^^^^^^^^^^^^^^^^^^^^^^ ^
typename FT = function<ostream&(ostream&,const IN&)>
>
void func(ostream& ss,const T& v,FT op = [](ostream& os,const IN&v)->ostream&{ return os << v; }) {
for (const auto& i: v) {
std::invoke(op,ss,i);
}
}