是否可以在本地匿名函数中使用周围模板函数的模板类型参数?我很确定我不能声明模板lambda ...
例如,我将如何做这样的事情:
template <typename T>
void TrimString(std::basic_string<T>& str, const std::locale& loc = std::locale())
{
// std::isspace as lambda unary predicate?
auto fn = [&loc](T c){ return std::use_facet<std::ctype<T>>(loc).is(std::ctype_base::space, c); };
// trim right
str.erase(std::find_if(str.rbegin(), str.rend(), std::not1(fn)).base(), str.end());
// trim left
str.erase(str.begin(), std::find_if(str.begin(), str.end(), std::not1(fn)));
}
目前,这会产生以下错误:
error C2039: 'argument_type' : is not a member of '`anonymous-namespace'::<lambda0>'
这是有道理的,因为lambda对周围模板函数中的参数T
没有任何线索。
我使用VS2010和gcc 4.7,但我不想使用boost。
有什么想法吗?
编辑:我认为问题是模板参数本身是错误的。而是使用lambda函数编译std::not1
。这是更详细的错误输出:
error C2039: 'argument_type' : is not a member of '`anonymous-namespace'::<lambda0>'
: see declaration of '`anonymous-namespace'::<lambda0>'
: see reference to class template instantiation 'std::unary_negate<_Fn1>' being compiled
with
[
_Fn1=`anonymous-namespace'::<lambda0>
]
: see reference to function template instantiation 'void TrimString<char>(std::basic_string<_Elem,_Traits,_Ax> &,const std::locale &)' being compiled
with
[
_Elem=char,
_Traits=std::char_traits<char>,
_Ax=std::allocator<char>
]
如果它是函数类型,你是否需要显式声明参数的类型?我不确定我做错了什么......
数目:
选项1:如果我不使用std::not1
而是否定lambda中的返回值,我会得到相同的行为而没有问题。
auto fn = [&loc](T c){ return !std::use_facet<std::ctype<T>>(loc).is(std::ctype_base::space, c); };
选项2:由于lambda不再等同于std::isspace
作为一元谓词的行为,因此函数对象构造函数转换也可以解决问题。
str.erase(std::find_if(str.rbegin(), str.rend(), std::not1(std::function<bool(T)>(fn))).base(), str.end());
答案 0 :(得分:9)
问题不是由在lambda中使用模板参数引起的,因为在构造lambda时参数已经被解析为类型。
问题是你定义的lambda不能与std::not1
结合使用,std::unary_function<argument_type,return_type>
需要std::not1
作为参数。
解决问题的最简单方法是不使用auto fn = [&loc](T c){ return !std::use_facet<std::ctype<T>>(loc).is(std::ctype_base::space,c); };
,而是否定lambda表达式中的预测权:
#include <string>
#include <algorithm>
#include <locale>
#include <iostream>
template <typename T>
void TrimString(std::basic_string<T>& str, const std::locale& loc = std::locale())
{
auto fn = [&loc](T c){ return !std::use_facet<std::ctype<T>>(loc).is(std::ctype_base::space,c); };
str.erase(std::find_if(str.rbegin(), str.rend(),fn).base(), str.end());
str.erase(str.begin(), std::find_if(str.begin(), str.end(), fn));
}
int main() {
std::basic_string<char> s(" hello ");
TrimString(s);
std::cout << s << std::endl;
return 0;
}
编译和使用GCC 4.7.0的完整代码变为:
hello
此输出
{{1}}
正如所料。
答案 1 :(得分:6)
您当然可以使用T
作为lambda表达式的参数类型。以下程序在GCC 4.5.1
上编译罚款:
include <iostream>
template<typename T>
void f(T arg)
{
auto print = [](T a) { std::cout << a << std::endl; };
print(arg);
}
int main() {
f(8899);
f("Nawaz");
return 0;
}
BTW,错误消息似乎表明问题出在其他地方,特别是在 namespace 范围内声明的lambda:
错误C2039:'argument_type':不是'`anonymous-namespace'的成员 ::&lt; lambda0&gt;'
编辑后,我只能说不要使用std::not1
。事实上,你甚至不需要它。你可以在lambda本身使用return !whatever-expression
。
答案 2 :(得分:2)
编辑:正如@Nawaz指出的那样,你的错误必须来自其他地方...我在下面描述的内容是过度的......
使用decltype
,您可以执行以下操作:
template <typename T>
void TrimString(std::basic_string<T>& str,
const std::locale& loc = std::locale(),
T arg = T())
{
auto fn = [&loc](decltype(arg) c){ return std::use_facet<std::ctype<T>>(loc).is(std::ctype_base::space, c); };
//...rest of your code
}
这是使用(或滥用)表达式decltype(arg)
评估为arg
类型的事实,在这种情况下是T
的类型。