3

私は少なくとも2週間問題にぶら下がっていて、理解できないものにブロックされ、SOで実際の問題を実際に指し示していない質問をしています(愚かな私です!)。最後になりましたが、この質問で私の頭痛の本当のポイントを見つけていたらよかったのにと思います。

特定の型にメンバーメソッドがあるかどうかを検出するためのヘルパーとしてテンプレート構造体を使用してきました。このテンプレート構造体は次のようになります。

template
<
    typename Type,
    typename Return,
    typename Parameter,
    Return (Type::*)(Parameter)
> struct W {};

の周りの主なアイデアstruct Wは、4番目のパラメーターとしてSFINAEトリックを使用してテストする必要があるメンバー関数へのメンバー関数ポインターを置くことです。前の質問で代替案が提案され、それは私が持っている多くの概念を理解するのに非常に役立ちました行方不明ですが、結局、それは私の本当の問題を解決しません。

私が取り組んでいるコードは、LinuxプラットフォームとWindowsプラットフォームの両方で機能する必要があります。Windowsに使用しているコンパイラは、Linux側のMSVC(Visual Stuido 2010 10.0)とgcc(Devian 4.4.5-8)です。問題は、同じコードがMSVCでコンパイルされないが、gccでコンパイルされることです(私はショックを受けました。通常は反対です。MSVCは標準に厳密ではないためです)。

問題の原因は、MSVCでのコンパイル中に、SFINAEアプローチがメソッドの検出に失敗することset::insertでした。この失敗を探すために、簡単なテストを作成しました。

#include <set>

int main(int argc, char **argv)
{
    typedef std::set<int> setint;

    std::pair<setint::iterator, bool> (setint::*p_1)(const setint::value_type &) = &setint::insert;
    W<setint, std::pair<setint::iterator, bool>, const setint::value_type &, &setint::insert> w_1;

    return 0;
}

前に述べたように、このサンプルはgccを使用して問題なくコンパイルされますが、MSVCを使用していると、次の宣言でエラーが発生しますw_1

error C2440: 'specialization' : cannot convert from 'overloaded-function' to 'std::pair<_Ty1,_Ty2> (__thiscall std::set<_Kty>::* )(const int &)'
    with
    [
        _Ty1=std::_Tree_const_iterator<std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>>>,
        _Ty2=bool,
        _Kty=int
    ]
    None of the functions with this name in scope match the target type

関数ポインタを作成している間は期待どおりに機能するため、コンパイルの宣言はp_1コンパイルされます。ただし、テンプレートパラメータと同じ署名ではありません。これがset::insert、SFINAEのシンボル置換中に検出が失敗する理由です。エラーテキストcannot convert from 'overloaded-function'は、何が起こっているのかについての手がかりを私に提供しません(または私の英語の理解が不十分なため、私は何も見つけることができません)。

一見、問題はシンボルの置換だと思っていましたが、MSVCとgccの両方で失敗した場合は理にかなっています。したがって、今のところ、問題がMSVCコンパイラ固有の方法であるかどうか疑問に思っています。

MSVCで失敗する理由と、gccとMSVCを同じように機能させる方法についての手がかりはありますか?

追加の質問:std::mapそして、赤黒木(またはandの下にあるもの)のMSVC実装の下でメソッドの戻り型としてstd::setネストされた型を提供しますが、gcc実装に同等のものはありませんか?_Pairib::insertmapset

編集:

冷静な答えを読んだ後、私はMSVCのstd::set実装を調べました。

std::setstd::_Treeは、チェックしたいメソッドを提供する派生クラスです。

// class std::_Tree, file xtree in the path 'VisualStudioPath/VC/include/'
_Pairib insert(const value_type& _Val)
    {    // try to insert node with value _Val, favoring right side
    return (insert(_Val, false));
    }

この挿入メソッドはstd::_Treeスコープではなくスコープに属しstd::setますが、パブリックスコープにあり、継承されたメソッドでもあるので、名前の置換中にアクセスできないのはなぜですか?

4

2 に答える 2

2

失敗の原因は、VC stdlibで、insertが実際にはsetクラステンプレート自体のメンバーではなく、継承されていることです。

テストケース、

template
<
    typename Type,
    typename Return,
    typename Parameter,
    Return (Type::*)(Parameter)
> struct W {};

struct A { void foo (int); };

struct B : public A {};

int main(int argc, char **argv)
{
    void (B::*p)(int) = &B::foo;
    // W<B, void, int, &B::foo> w; // error
    W<A, void, int, &A::foo> w;

    return 0;
}

PS。エラーは、一部のGCCと一部のMSVCの両方でのエラーです。

しかし、それはパブリックスコープにあり、継承されたメソッドでもあるので、なぜアクセスできないのかわかりません。

この場合、変換は許可されないため、「14.3.2。テンプレートの非型引数[#5]」

メンバー関数への型ポインターの非型テンプレートパラメーターの場合、template-argumentがタイプstd :: nullptr_tの場合、nullメンバーポインター変換(4.11)が適用されます。それ以外の場合、変換は適用されません。template-argumentがオーバーロードされたメンバー関数のセットを表す場合、一致するメンバー関数がセット(13.4)から選択されます。

PPS。したがって、変換を明示的に行い、出来上がりです。可能な基本クラスを気にする必要はありません。

W<setint,
  std::pair<setint::iterator, bool>,
  const setint::value_type &,
  static_cast<std::pair<setint::iterator, bool> (setint::*)(const setint::value_type &)> (&setint::insert)> w_1;
于 2012-11-26T10:58:30.223 に答える
0

この質問によると、Standardは、Standardオブジェクトのメンバーへのメンバー関数ポインターを取得できることを定義していません。

そして_Pairib、これはMSVC実装の詳細です。当然、GCCでも同様のものは見つかりません。

于 2012-11-26T10:19:51.777 に答える