2016-06-23 3 views
0

私は、あまり書かれていないレガシーコードで作業しており、Microsoft Visual StudioとVisual C++コンパイラでのみコンパイルします。 GCC、G ++、またはClangは、すべてビルド時間エラーのためにコードをコンパイルできません。私はの構造を維持しながら、このコードセグメントをリファクタリングするための最良の方法であるかを知りたいクラス宣言でイテレータをtypedefiningする問題

#include <map> 
#include <set> 
#include <iomanip> 
#include <string> 
#include <cmath> 
#include <iterator> 

#include <unordered_map> 
#include <bits/unique_ptr.h> 

#define HASH_MAP unordered_map 

using namespace std; 

namespace XYZ { 
     class abc { 
      public: 
       typedef HASH_MAP<double, abc> MAP; // This is the problem ? 
       typedef MAP::iterator Iterator; 
       typedef MAP::const_iterator ConstIterator; 
       typedef pair<double, abc> Pair; 

       bool less(abc::Pair& a, abc::Pair& b) { return a.first < b.first; } 

      public: 
       abc() {} 
       ~abc() { } 

     }; 
    } 

:私は、クラス宣言内class typeSTLコンテナをインスタンス化し、次のクラス宣言に問題を絞り込んていますコード。例えば、私はポインタタイプ(すなわち、typedef HASH_MAP<double, XYZ*> MAP)でMAPの定義をしようとしていましたが、この変更はGCCコンパイラではうまくいきましたが、ポインタタイプに変更しているのでコードベースを深く掘り下げてこのクラスのコードベースのほとんどは、他の依存コードで重要な役割を果たしています。

元のコードベースに大きな変更を加える必要のないこの問題を修正する代替方法があるかどうかは疑問でした。私は、friendクラスを類似させるという考え方で考えていました。続き

は、コンパイラのエラーです:

In file included from /usr/include/c++/4.8/bits/stl_algobase.h:64:0, 
       from /usr/include/c++/4.8/bits/stl_tree.h:61, 
       from /usr/include/c++/4.8/map:60, 
       from /home/user/work/wxy.h:4, 
       from /home/user/work/abc.h:4, 
       from /home/user/work/abc.cpp:1: 
/usr/include/c++/4.8/bits/stl_pair.h: In instantiation of ‘struct std::pair<const double, XYZ::abc>’: 
/usr/include/c++/4.8/type_traits:615:28: required from ‘struct std::__is_destructible_impl<std::pair<const double, XYZ::abc> >’ 
/usr/include/c++/4.8/type_traits:637:12: required from ‘struct std::__is_destructible_safe<std::pair<const double, XYZ::abc>, false, false>’ 
/usr/include/c++/4.8/type_traits:652:12: required from ‘struct std::is_destructible<std::pair<const double, XYZ::abc> >’ 
/usr/include/c++/4.8/type_traits:116:12: required from ‘struct std::__and_<std::is_destructible<std::pair<const double, XYZ::abc> >, std::__is_direct_constructible_impl<std::pair<const double, XYZ::abc>, const std::pair<const double, XYZ::abc>&> >’ 
/usr/include/c++/4.8/type_traits:817:12: required from ‘struct std::__is_direct_constructible_new_safe<std::pair<const double, XYZ::abc>, const std::pair<const double, XYZ::abc>&>’ 
/usr/include/c++/4.8/type_traits:895:12: [ skipping 4 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ] 
/usr/include/c++/4.8/type_traits:968:12: required from ‘struct std::__is_copy_constructible_impl<std::pair<const double, XYZ::abc>, false>’ 
/usr/include/c++/4.8/type_traits:974:12: required from ‘struct std::is_copy_constructible<std::pair<const double, XYZ::abc> >’ 
/usr/include/c++/4.8/bits/alloc_traits.h:540:12: required from ‘struct std::__is_copy_insertable<std::allocator<std::pair<const double, XYZ::abc> > >’ 
/usr/include/c++/4.8/bits/alloc_traits.h:560:63: required by substitution of ‘template<class _Alloc> using __check_copy_constructible = std::__allow_copy_cons<std::__is_copy_insertable<_Alloc>::value> [with _Alloc = std::allocator<std::pair<const double, XYZ::abc> >]’ 
/usr/include/c++/4.8/bits/unordered_map.h:97:11: required from ‘class std::unordered_map<double, XYZ::abc>’ 
/home/user/work/abc.h:27:20: required from here 
/usr/include/c++/4.8/bits/stl_pair.h:102:11: error: ‘std::pair<_T1, _T2>::second’ has incomplete type 
     _T2 second;    /// @c second is a copy of the second object 
     ^
In file included from /home/user/work/abc.cpp:1:0: 
/home/user/work/abc.h:24:11: error: forward declaration of ‘class XYZ::abc’ 
    class abc { 
     ^
+4

名前空間は、おそらく 'std :: unordered_map'のテンプレート引数になりますか? – user2079303

+0

は 'typedef'インスタンス化なしです – user463035818

+1

なぜ' public: 'が2回宣言されたのか不思議です。そして、クラス 'abc'または' namespace XYZ'には左 '}'がありません。 – NonCreature0714

答えて

3

イテレータとの問題は(何らかの理由で、ちょうどtypedefです)です。それらをクラスコードの外に移動して、定義の時点でクラス定義が完了するようにすると、コンパイルされます(g ++でコンパイルされます)。おそらく、IteratorからMAP_Iteratorなどに名前を変更する必要があります。あなたのコメントの後に、abc(元のクラス名)というクラスにイテレータのtypedefを入れて、クライアントコードとのソースの互換性を保持することを考えました(私は、クライアントコードに必要な変更が管理可能であると想像することができます)。 。実際のクラス定義は、クライアントコードが明示的に使用する必要のない基本クラスに移動されます。このマップには、基本クラスのオブジェクトが格納されます。このオブジェクトには、真を格納または取得するときにスライスおよび逆変換が含まれます。abcおそらくマップ内の値への参照をabcで保持することはできませんが、以下の単純な値ベースの例(イテレータを使用)は機能します。ソースコードにはいくつかのコメントがあります。

#include <unordered_map> 
#include <iostream> 
using namespace std; 

// The "original" abc 
class abcBase 
{ 
     public: 

     typedef unordered_map<double, abcBase> MAP; // This is the problem ? 
      typedef pair<double, abcBase> Pair; 
      bool less(abcBase::Pair& a, abcBase::Pair& b) { return a.first < b.first; } 
      string tag; 
     public: 
      abcBase(string t): tag(t){} 
      abcBase() = default; 
      ~abcBase() { } 
}; 

// The abc presented to the users for source compatibility. 
// There is a conversion 
// from base to derived via constructor. 
// 
// Note that a MAP 
// holds abcBase objects, not abc objects! We need to convert them 
// when we store and when we read. 
// Conversion derived -> base is via slicing 
// (which does not do any harm as long as we do not define 
// data members in derived). 
class abc: public abcBase 
{ 
    public: 
    // conversion constructor 
    abc(const abcBase &b): abcBase(b){} 
    abc(string t): abcBase(t){} 
    abc() = default; 
    typedef MAP::iterator Iterator; 
    typedef MAP::const_iterator ConstIterator; 
}; 

int main() 
{ 
    abc::MAP m; 
    abc a("a"),b("b"),c("c"); 
    m[1.0] = a; // conversion abc -> abcBase ... 
    m[2.0] = b; 
    m[3.0] = c; 

    a = m[1.0]; // conversion abcBase -> abc via ctor 

    for(abc::Iterator i = m.begin(); i != m.end(); ++i) 
    { 
     cout << "key: " << i->first << ", val: " << i->second.tag << endl; 
    } 
    return 0; 
}  
+0

解決に感謝します。このコードをコンパイルしましたが、クライアントコードでは 'iterator'がこのクラスの一部ではないので失敗します。したがって、クラスインスタンスが宣言され、そのイテレータが呼び出されるたびに、クラスインスタンスはそれに不満を持ちます。クラスの 'iterators'を作るための提案はありますか? – kishansudu

+0

助けてくれてありがとう!あなたのソリューションは問題を解決しました。クライアントコードに名前空間識別子を使用する。 – kishansudu

+0

ああ、良い!私はちょうど派生クラスの構築で、更新されたソリューションを投稿しましたが、それはハックの何か... –

0

あなたはとてもあなたがC++ 11を使用しているstd::unordered_mapを使用しています。

の代わりにstd::unique_ptrtypedef HASH_MAP<double, std::unique_ptr<XYZ>> MAPの代わりに)を使用すると、次の変更を減らすのに役立つと思います。

例では、次のコードは、

#include <utility> 
#include <memory> 
#include <unordered_map> 

using namespace std; 

#define HASH_MAP unordered_map 

namespace abc { 
    class XYZ { 
     private: 
     int _test; 

     public: 
     typedef HASH_MAP<double, std::unique_ptr<XYZ>> MAP; // This is the problem ? 
     typedef MAP::iterator Iterator; 
     typedef MAP::const_iterator ConstIterator; 
     typedef pair<double, std::unique_ptr<XYZ>> Pair; 

     bool less(XYZ::Pair& a, XYZ::Pair& b) { return a.first < b.first; } 

     public: 
     XYZ():_test(0) {} 
     ~XYZ() { } 

     // Some function definitions 
    }; 
}; 


int main() 
{ 
    return 0; 
} 

は明らかに私はあなたの名前空間を想定していコンパイルabcであり、あなたのクラス名はXYZです。名前空間をマップに配置することはできません。

p.s .:申し訳ありませんが、私の悪い英語です。

+0

未加工のポインタの代わりに 'unique_ptr'を使用する方がスタイルは良いでしょうが、それはクライアントコードの変更量を減らすでしょうか? –

+0

@ PeterA.Schneider - たくさんありませんが、解決のために 'delete'部分を避けることができます – max66

+0

@ max66ありがとうございます。私は 'unique_ptr'ではなくrawポインタの前にポインタのルートを取っていました。クライアントコードベースを大きく変更する必要があるようです。 – kishansudu