2011-06-21 15 views
3

概要奇妙なエラーがC2275 ...ラムダ関数を呼び出すメンバ関数テンプレートとラムダ何らかの理由

、私のメンバ関数テンプレートを使用して表現として、この種の不正使用はエラーC2275とコンパイルに失敗します...この型を式として不正に使用しますが、関数を自由な関数に移動して正しくコンパイルすると、

詳細

まず私はvectorfunctionのインスタンスを保持し、基本クラスを持っています。派生したクラスのみがadd_externalを呼び出してvectorfunctionのインスタンスを追加できます。すべてのfunctionインスタンスは、invoke_externalsを呼び出すことによって公的に呼び出すことができます。派生クラスは、lambdaをfunctionインスタンスとして追加します。これらのラムダは、基底クラス関数テンプレートinvoke_internalを別の「内側の」ラムダと呼びます。 invoke_internalにテンプレートパラメータinvoke_internalに「内側」ラムダを実行するときに、明示的にキャッチされる例外タイプされています。そして、私はlogic_errorruntime_error例外をスロー2つのささいな無料の機能を持っている

using namespace std; 

class base 
{ 
public: 
    void invoke_externals() 
    { 
     for (auto it = funcs_.begin(); it != funcs_.end(); ++it) 
     { 
      (*it)(); 
     } 
    } 

protected: 
    void add_external(function<void(void)> func) 
    { 
     funcs_.push_back(func); 
    } 

    template <typename T> 
    void invoke_internal(function<void(void)> func) 
    { 
     try 
     { 
      func(); 
     } 
     catch (const T&){} 
     catch (...){} 
    } 

    vector<function<void(void)>> funcs_; 
}; 

。これらの関数は、invoke_internalで呼び出され、「内側」ラムダで使用される:derivedクラスのコンストラクタにおいて

void throws_logic_error() 
{ 
    throw logic_error(""); 
} 

void throws_runtime_error() 
{ 
    throw runtime_error(""); 
} 

二ラムダはadd_externalで添加されます。これらのラムダのそれぞれは、invoke_internalに "内側"のlmbdasと呼ばれています。 invoke_internalへの最初の呼び出しは、throws_logic_errorがスローするlogic_errorを明示的にキャッチします。 invoke_internalへの2回目の呼び出しでは、throws_runtime_errorが投げるruntime_errorを明示的にキャッチします。

class derived : public base 
{ 
public: 
    derived() 
    { 
     add_external([this]() 
     { 
      invoke_internal<logic_error>([]() 
      { 
       throws_logic_error(); 
      }); 
     }); 

     add_external([this]() 
     { 
      invoke_internal<runtime_error>([]() 
      { 
       throws_runtime_error(); 
      }); 
     }); 
    } 
}; 

一緒全てを結びつけるために、derivedがインスタンス化され、invoke_externalsderivedコンストラクタで添加「外部」ラムダを呼び出すために呼び出されます。これらの「外部」ラムダは順番に「内側」ラムダを起動するとスローされた例外を明示的にキャッチされます。

しかし

int wmain(int, wchar_t*[]) 
{ 
    derived().invoke_externals(); 

    return 0; 
} 

問題、上記ではコンパイルできません:

error C2275: 'std::logic_error' : illegal use of this type as an expression 
error C2275: 'std::runtime_error' : illegal use of this type as an expression 

... コンストラクタのinvoke_internalへのコールに対して発行されます。

invoke_internalbaseから外に出して自由にすると、コンパイルされます。

質問

なぜ私が表現関数テンプレートがbaseメンバーであるとして、このタイプのエラーC2275 ...不正使用を入手できますか?

注:私の本当の人生のシナリオで機能が実際にさまざまな方法でそのクラスの状態を使用しないのでbaseのうち、問題のある機能を移動するには最適ではありません。

答えて

5

@ seheさんのおかげで、私はVS2010でこれをテストできました。次のコードは動作します:

derived() 
{ //      vvvvvvvvvvvvvv 
    add_external([this]() { this->template invoke_internal<logic_error>([]() { throws_logic_error(); }); }); 

    add_external([this]() { this->template invoke_internal<runtime_error>([]() { throws_runtime_error(); }); }); 
} //      ^^^^^^^^^^^^^^ 

は型が使用されたテンプレートは、といった検出されなかったことを、why.Generallyあなたは手段を取得し、エラーを私に聞かないでください。これが唯一の依存型/ネストされたテンプレートを使用して行われるべきと直接テンプレートは以下のコンパイラ(当たり前)に指示します(図に示すように)問題のテンプレート、前templateで解決することができ、通常

template Foo<int>; // explicitly instantiate the Foo class template for int 

を今:それは自分自身で間違っているだろう明示的なインスタンス、次のようになり、他ので、私たちは、そのかかわらず、前this->を必要としています。 strangly、この問題もここで発生し、コンパイラの制限のように見える@seheにしか同意できません。

+0

良い考え。ありがとう - これは便利かもしれない – sehe

3

これはコンパイラの制限のようです。

#include <vector> 
#include <functional> 
#include <stdexcept> 
using namespace std; 

class base 
{ 
    public: 

     void invoke_externals() 
     { 
      for (auto it = funcs_.begin(); it != funcs_.end(); ++it) 
      { 
       (*it)(); 
      } 
     } 

    protected: 

     void add_external(function<void(void)> func) 
     { 
      funcs_.push_back(func); 
     } 

     template <typename T> 
      void invoke_internal(function<void(void)> func) 
      { 
       try 
       { 
        func(); 
       } 
       catch (const T&) 
       { 
       } 
       catch (...) 
       { 
       } 
      } 

     vector<function<void(void)>> funcs_; 
}; 

void throws_logic_error() { throw logic_error(""); } 
void throws_runtime_error() { throw runtime_error(""); } 

class derived : public base 
{ 
    public: 

     derived() 
     { 
      add_external([this]() { invoke_internal<logic_error>([]() { throws_logic_error(); }); }); 

      auto g = [this]() { invoke_internal<runtime_error>([]() { throws_runtime_error(); }); }; 
      add_external(g); 
     } 
}; 

int main(int, char*[]) 
{ 
    derived().invoke_externals(); 

    return 0; 
} 
:それは誰にもTU、私がコンパイルし、実際に適切にこれを過ぎて/コピーするためにいくつかの仕事をした、試してみたい場合は--std = C++ 0xの

とGCC 4.6に罰金コンパイル

+0

コンパイル可能なコード例をありがとう、私の答えを参照してください。 :) – Xeo

+0

ああ、コンパイラの制限。標準とは何ですか?それは単なるバグ*であり、単なる制限ではない? –

+1

@Johann:MSVC10はlambdaをN2927よりも先に実装しています。だから、これはもうFDISにはない言い回しに基づいています。 MSVC11はN3290に基づいてラムダをサポートします。 – ildjarn

関連する問題