如何在lambda中使用模板类型参数?

AJG*_*G85 6 c++ lambda templates c++11

是否可以在本地匿名函数中使用周围模板函数的模板类型参数?我很确定我不能声明模板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)));
}
Run Code Online (Sandbox Code Playgroud)

目前,这会产生以下错误:

error C2039: 'argument_type' : is not a member of '`anonymous-namespace'::<lambda0>'
Run Code Online (Sandbox Code Playgroud)

这是有道理的,因为lambda T对周围模板函数的参数没有任何线索.

我使用VS2010和gcc 4.7,但我不想使用boost.

有任何想法吗?

编辑:我认为问题是模板参数本身似乎是错误的.而是使用std::not1lambda函数编译.这是更详细的错误输出:

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>
          ]
Run Code Online (Sandbox Code Playgroud)

如果它是函数类型,您是否需要显式声明参数的类型?我还不确定我做错了什么...

回答:

选项1:如果我不使用std::not1而是否定lambda中的返回值,我会得到相同的行为而没有问题.

auto fn = [&loc](T c){ return !std::use_facet<std::ctype<T>>(loc).is(std::ctype_base::space, c); };
Run Code Online (Sandbox Code Playgroud)

选项2:由于lambda不再等同于std::isspace作为一元谓词的行为,因此函数对象构造函数转换也可以解决问题.

str.erase(std::find_if(str.rbegin(), str.rend(), std::not1(std::function<bool(T)>(fn))).base(), str.end());
Run Code Online (Sandbox Code Playgroud)

jog*_*pan 9

问题不在于使用拉姆达内模板参数引起的,因为拉姆达被创建时的参数已经被解析为一个类型的时候.

问题是你定义的lambda不能组合std::not1,这需要作为参数a std::unary_function<argument_type,return_type>.

解决问题的最简单方法是不使用std::not1,而是否定lambda表达式中的预测权:

auto fn = [&loc](T c){ return !std::use_facet<std::ctype<T>>(loc).is(std::ctype_base::space,c); };
Run Code Online (Sandbox Code Playgroud)

编译和使用GCC 4.7.0的完整代码将变为:

#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;
}
Run Code Online (Sandbox Code Playgroud)

这输出

hello
Run Code Online (Sandbox Code Playgroud)

正如所料.


Naw*_*waz 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;
}
Run Code Online (Sandbox Code Playgroud)

看看自己:http://ideone.com/l32Z6

顺便说一句,错误消息似乎表明问题出在其他地方,特别是在命名空间范围内声明的lambda :

错误C2039:'argument_type':不是'`anonymous-namespace' :: <lambda0>'的成员


编辑后,我只能说不要使用std::not1.事实上,你甚至不需要它.你可以return !whatever-expression在lambda中使用它.