6

ローカル無名関数内で周囲のテンプレート関数からテンプレート型引数を使用することは可能ですか? テンプレートラムダを宣言できないと確信しています...

たとえば、次のようなことを行うにはどうすればよいですか。

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

Tラムダは周囲のテンプレート関数からの引数についての手がかりがないため、これは理にかなっています。

VS2010 と gcc 4.7 を使用していますが、boost は使用したくありません。

何か案は?

編集:問題はテンプレート引数自体であるという私の仮定は間違っていたようです。むしろ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ラムダで返された値を使用せずに否定すると、問題なく同じ動作が得られます。

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

オプション 2: ラムダは、単項述語としてどのように動作するかと同等ではないためstd::isspace、関数オブジェクト コンストラクター キャストもトリックを行います。

str.erase(std::find_if(str.rbegin(), str.rend(), std::not1(std::function<bool(T)>(fn))).base(), str.end());
4

3 に答える 3

9

ラムダが構築された時点でパラメータはすでに型に解決されているため、ラムダ内でテンプレート パラメータを使用しても問題は発生しません。

問題は、定義したラムダを と組み合わせることができないことです。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); };

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

これは出力します

hello

予想通り。

于 2012-06-21T01:36:51.223 に答える
6

Tラムダ式のパラメーター型として使用できることは間違いありません。次のプログラムは、 の罰金をコンパイルします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;
}

自分自身を参照してください: http://ideone.com/l32Z6

ところで、エラーメッセージは、問題が別の場所にあることを示しているようです。具体的には、名前空間スコープで宣言されたラムダを使用しています。

エラー C2039: 'argument_type' : '`anonymous-namespace' ::<lambda0>'のメンバーではありません


あなたの編集の後、私が言えることは、std::not1それから使用しないでください. 実際、あなたもそれを必要としません。return !whatever-expressionラムダ自体で使用できます。

于 2012-06-21T01:20:41.260 に答える
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)評価されるという事実を使用(または悪用)しています。argT

于 2012-06-21T01:15:43.990 に答える