3

私のプロジェクトのいくつかでは、次のコード:

#include <functional>

class SmallClass
{
public:
    int x1, y1;

    void TestFunc()
    {
        auto BadLambda = [&]()
        {
            int g = x1 + 1; //ok
            int h = y1 + 1; //c2296

            int l = static_cast<int>(y1); //c2440
        };

        int y1_copy = y1; //it works if you create a local copy
        auto GoodLambda = [&]()
        {
            int h = y1_copy + 1; //ok
            int l = this->y1 + 1; //ok
        };
    }
};

生成する

エラー C2296: '+': 不正です。左側のオペランドの型は 'double (__cdecl *)(double)' です

または代わりに

エラー C2440: 'static_cast': 'double (__cdecl *)(double)' から 'int' に変換できません

あなたは絵を手に入れます。値でキャッチした場合にも発生します。

エラーはメンバー名「y1」に紐付いているようです。それは、さまざまなクラス、さまざまなプロジェクトで、(一見) y1 の任意の型で発生しました。たとえば、次のコード:

[...]
MyClass y1;

void TestFunc()
{
    auto BadLambda = [&]()->void
    {
        int l = static_cast<int>(y1); //c2440
    };
}

次の両方のエラーが生成されます。

エラー C2440: 'static_cast' : 'MyClass' から 'int' に変換できません この変換を実行できるユーザー定義変換演算子がないか、演算子を呼び出すことができません

error C2440: 'static_cast' : 'double (__cdecl *)(double)' から 'int' に変換できません この変換が可能なコンテキストはありません

「機能的」ライブラリにリンクされているようです。「機能」のみを含む最小限のプロジェクトで(私のマシンで)発生します(はい、括弧の間にあるはずですが、HTMLで失敗します)。

既知のバグではないようで、途方に暮れています。なぜこれが起こるのかについてのアイデアはありますか? (回避策は必要ありません。コードには既にいくつかあります)。

編集:実際、math.hの関数に関連しています:

_CRT_NONSTDC_DEPRECATE(_cabs) _CRTIMP double __cdecl cabs(In struct _complex _X); _CRT_NONSTDC_DEPRECATE(_j0) _CRTIMP double __cdecl j0(In double _X); _CRT_NONSTDC_DEPRECATE(_j1) _CRTIMP double __cdecl j1(In double _X); _CRT_NONSTDC_DEPRECATE(_jn) _CRTIMP double __cdecl jn(In int _X, In double _Y); _CRT_NONSTDC_DEPRECATE(_y0) _CRTIMP double __cdecl y0(In double _X); _CRT_NONSTDC_DEPRECATE(_y1) _CRTIMP double __cdecl y1(In double _X); _CRT_NONSTDC_DEPRECATE(_yn) _CRTIMP double __cdecl yn(In int _X, In double _Y);

これらの関数名のいずれかを使用すると、バグが発生します。math.h、cmath、または機能をインクルードするときに発生します。これらの名前がどのようにして私のラムダ式の範囲に入ったのか、誰かが手がかりを持っているのではないでしょうか?

編集:解決しました。これは、VS2010 (およびおそらく他の古いコンパイラ) でのラムダ名解決の問題です。グローバル名を定義する場合、または「名前空間 x を使用する」を使用する場合は、ラムダで非修飾名を使用しないでください。

Visual Studio 2010 Express バージョン 10.0.40219.1 SP1Rel を使用します。

4

3 に答える 3

3

の使用はin (第 2 種 Bessel 関数、次数 1)とy1競合します。これが、名前空間が Good Thing(sm) であり、 で迂回してはならない理由です。(ただし、問題ありません。)もちろん、すべての C++ヘッダーがすべての名前を namespace にのみ適切に配置するわけではありませんが、配置する必要があります。数学ライブラリに短い名前が多すぎます。y1<cmath>std::using namespace std;using std::stringcmathstd

C++ の名前解決規則は複雑です。私は、ほこりっぽいコーナーをすべて理解しているふりをしているわけではありません。ラムダ内の非修飾名が、メンバー関数の実際の本体内の非修飾名とまったく同じ方法で検索されない可能性は十分にあります。メンバー関数の外では、修飾されていない名前は、既に宣言されているクラス メンバーのみを参照できます。(this->y1ただし、修飾されていない名前ではありません。)


編集:ラムダで誤った名前解決規則を適用する VC10 のバグであることが判明しました。ラムダ式の名前解決のバグが 報告されましたが、これらのバグは VC12 で修正済みとしてマークされています (とは言っても、修正済みとしてマークされていないバグ レポートを見つける方法がわかりません)。私は以下の私の提案を支持しますが、明示的な使用に関するものthis->はおそらくもっと議論の余地がありますが、予期しない名前の検索で何度かやけどを負ったことがあり、明示的な修飾が​​役立つ場合があります。


全体として、私の提案は次のとおりです。

1) 絶対に使用using namespace std;しないでください。

this->2)それがあなたの意図するものである場合は常に使用してください。(または、少なくとも、_クラス データ メンバーの末尾規則を使用します。)


編集stdC ライブラリ ヘッダーによる名前空間の使用。

17.6.1.2(4): ただし、C++ 標準ライブラリでは、宣言 (C でマクロとして定義されている名前を除く) は名前空間 std の名前空間スコープ (3.3.6) 内にあります。これらの名前が最初にグローバル名前空間スコープ内で宣言され、次に明示的な using 宣言 (7.3.3) によって名前空間 std に挿入されるかどうかは指定されていません。

つまり、名前はグローバル名前空間に存在する必要がありstd::、存在する可能性もあります。したがって、std::一貫して使用しても害はありません。役に立たないかもしれませんが、これらの名前をグローバル名前空間に挿入しない将来の標準ライブラリから保護することもできます。

于 2012-11-06T06:24:06.917 に答える
1

正直なところ、int から int にキャストする意味がわかりません。あなたは簡単に書くことができます:

int l = y1;

しかし、本当に int を int に変換したい場合は、以下のコードが機能します。

int l = static_cast<int>(y1); 
于 2012-11-06T04:53:24.197 に答える
0

クラスは私の VS2010 でコンパイルされます。編集したのは 1 行だけです。int l = static_cast(y1); //c2440

に変更されました:int l = static_cast<int>(y1);

一見クールなバグですが、変数の命名には適切な規則を使用してみてください。説明的で長すぎないようにします。ロブ・パイクとカーニハンによる「プログラミングの実践」という本を読んで、変数の命名と一貫したスタイルと書式設定の使用についてより良い視点を得てください。

編集:

#include <cmath>using namespace std;。エラーは発生しませんが、 をclass MyClass{};作成してオブジェクトを作成するとMyClass y1、 というエラーが発生し"..previous definition 'function'"ます。y1内部クラスはSimpleClass影響を受けません。

于 2012-11-06T04:50:38.217 に答える