How to use template type argument in lambda?

Is it possible to use a template type argument from the surrounding template function in a local anonymous function? I am sure that I cannot declare a lambda pattern ...

For example, how could I do something like this:

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))); } 

This currently creates the following error:

 error C2039: 'argument_type' : is not a member of '`anonymous-namespace'::<lambda0>' 

Which makes sense since lambda has no idea about the argument T from the surrounding template function.

I am using VS2010 and gcc 4.7, but I do not want to use boost.

Any ideas?

Edit: It seems like I was mistaken in my assumption that the problem was itself a template argument. Rather, it is using std::not1 compiled using a lambda function. Here is a more detailed error output:

 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> ] 

Do you need to explicitly declare an argument type if it is a function type? I'm not sure what I'm doing wrong yet ...

Answers:

Option 1: If I do not use std::not1 and instead deny the return value in lambda, I get the same behavior without problems.

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

Option 2: Since lambda is no longer equivalent to how std::isspace behaves like a unary predicate, the object constructor object object also does the trick.

 str.erase(std::find_if(str.rbegin(), str.rend(), std::not1(std::function<bool(T)>(fn))).base(), str.end()); 
+6
source share
3 answers

You can certainly use T as the parameter type of a lambda expression. The following program compiles fines on 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; } 

See for yourself: http://ideone.com/l32Z6

By the way, the error message seems to indicate that the problem is somewhere else, in particular with the lambda declaration in the namespace area:

error C2039: 'argument_type': not a member of '' anonymous namespace :: <lambda0> '


After your EDIT, all I can say is that don't use std::not1 . In fact, you do not even need it. You can use return !whatever-expression in lambda itself.

+6
source

The problem is not caused by using the template parameter inside the lambda, since the parameter was already resolved to the type at the time the lambda was built.

The problem is that the lambda you specified cannot be combined with std::not1 , which requires a std::unary_function<argument_type,return_type> as an argument.

The easiest way to solve the problem is to not use std::not1 and instead deny the prediction directly in the lambda expression:

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

The full code that compiles and works with GCC 4.7.0, then becomes:

 #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; } 

Displays

 hello 

as was expected.

+9
source

Change As @Nawaz points out, your error should appear elsewhere ... what I describe below is redundant ...

Using decltype , you can do something like the following:

 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 } 

This exploits (or abuses) the fact that decltype(arg) evaluates to type arg , which in this case is type T

+2
source

Source: https://habr.com/ru/post/918620/


All Articles