2017-03-08 3 views
1

私は移行テーブル実行時にロードされたステートマシンを書いてきたクラスのメンバ関数への文字列のマップへのスマートポインタを格納して、不完全な型のために失敗しないようにする方法?


背景。各遷移にかかるアクションは文字列として格納されます。文字列は、ステートマシンクラスのメンバ関数を指すstd::functionオブジェクトに変換されます。イベントが発生し、遷移すると、その関数が呼び出されます。


問題


実行時に呼び出される関数を決定する前に、私はこの戦略を成功裏に使用されています。残念ながら、私は次のようなエラーに実行してきた:


    を撮影

    error: return type 'XStMachine::TrFunc {aka class std::function<void (XStMachine::*)(const EventData&)>}' is incomplete

    それとも

    invalid use of incomplete type


    手順

  1. GoogleとStackoverflowに相談しました。私はタイプが不完全な場所から定義を取り出すことを含む多くのアイデアを得ました。残念ながら、私は正常に動作するようにはできませんでした。

  2. unique_ptrの代わりに未加工のポインタを使用してみましたが、魔法のように動作することがわかりました。

  3. 私は不完全な型を扱う方法shared_ptrunique_ptrとの差に少し読んでしまいました。私はshared_ptrを試しましたが、それは私の問題を解決しませんでした。

  4. フレンドクラスの宣言の時までに、タイプが全体と見なされることを願って、friendクラスを自分のステートマシンに作成しようとしました。私はこれを働かせることができませんでした。

  5. 最後に、次の最小限の例(エラーを再現するコードのコメントを外してください)を作成しました。これは、問題が発生したことを示しています。http://coliru.stacked-crooked.com/a/791092c7ca8fff24となりました。 :)


ソースコード


#include <iostream> 
#include <string> 
#include <functional> 
#include <memory> 
#include <map> 
#include <iomanip> 

using namespace std; 

struct EventData 
{ 
    unsigned int x; 
}; 

class Friendly; // Required for compiling the code. Why? 

class XStMachine 
{ 
     friend class Friendly; 
     unique_ptr<Friendly> fPtr; //-- Doesn't compile if Friendly is not fwd. declared 
     unsigned int y; 
     unsigned int z; 
    public: 
     typedef void(XStMachine::*TrFuncPtr)(EventData const&); 
     typedef std::function<TrFuncPtr> TrFunc; 
    private: 
     // map<string, TrFunc> fMap; //-- Doesn't compile because TrFunc is incomplete 
     // unique_ptr<map<string, TrFunc>> fMap; // Doesn't compile; incomplete type. 
     map<string, TrFunc> *fMap; // Compiles with incomplete type. 
    protected: 
     void tranFunc1(EventData const &d) 
     { 
      y = d.x; 
     } 

     void tranFunc2(EventData const &d) 
     { 
      z = d.x;  
     } 
    public: 
     XStMachine() 
     { 
      // Code to init fMap 
     } 

     // The code below doesn't compile. incomplete type. 
     TrFunc getTranFunc(std::string const &s) 
     { 
      return (*fMap)[s]; 
     } 

     ~XStMachine() 
     { 
     } 
}; 

class Friendly 
{ 
    // unique_ptr<map<string, XStMachine::TrFunc> fMap; // Doesn't compile, the type is incomplete. 
    public: 
     Friendly() 
     { 
      // Code to allocate and init fMap 
     } 

     // Dosen't compile if defined here because the return type is incomplete. 
     //XStMachine::TrFunc& getTranFunc(std::string const&) 
     //{ 
      // return (*fMap)[s]; 
     //} 
}; 
// The type is incomplete -> Will this work inside a separate cpp file? 
//XStMachine::TrFunc& getTranFunc(std::string const &s) 
//{ 
    // Weird - Can't access protected members though we're friends. :/ 
    /* 
    static map<string, XStMachine::TrFunc> fMap = {{"tranFunc1", function(&XStMachine::tranFunc1)}, 
                {"tranFunc2", function(&XStMachine::tranFunc2)} 
                };  
    */ 
    //return fMap[s]; 
//} 

int main() { 
    cout << "I need to understand incomplete types." << endl; 
    return 0; 
} 

Coliru(GCC 6からフル・エラー出力。3、C++ 14)


main.cpp: In member function 'XStMachine::TrFunc XStMachine::getTranFunc(const string&)': 
main.cpp:48:3: error: return type 'XStMachine::TrFunc {aka class std::function<void (XStMachine::*)(const EventData&)>}' is incomplete 
    { 
^
In file included from /usr/local/include/c++/6.3.0/bits/stl_algobase.h:64:0, 
       from /usr/local/include/c++/6.3.0/bits/char_traits.h:39, 
       from /usr/local/include/c++/6.3.0/ios:40, 
       from /usr/local/include/c++/6.3.0/ostream:38, 
       from /usr/local/include/c++/6.3.0/iostream:39, 
       from main.cpp:1: 
/usr/local/include/c++/6.3.0/bits/stl_pair.h: In instantiation of 'struct std::pair<const std::__cxx11::basic_string<char>, std::function<void (XStMachine::*)(const EventData&)> >': 
/usr/local/include/c++/6.3.0/bits/stl_map.h:481:10: required from 'std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = std::__cxx11::basic_string<char>; _Tp = std::function<void (XStMachine::*)(const EventData&)>; _Compare = std::less<std::__cxx11::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::__cxx11::basic_string<char>, std::function<void (XStMachine::*)(const EventData&)> > >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = std::function<void (XStMachine::*)(const EventData&)>; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = std::__cxx11::basic_string<char>]' 
main.cpp:49:23: required from here 
/usr/local/include/c++/6.3.0/bits/stl_pair.h:196: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 main.cpp:3:0: 
/usr/local/include/c++/6.3.0/functional:1526:11: note: declaration of 'class std::function<void (XStMachine::*)(const EventData&)>' 
    class function; 
      ^~~~~~~~ 

目的


プライマリ:サンプルコードで何が起こっているのかを理解し、それを修正します。

セカンダリ:不完全なタイプが何であるかを明確に把握して、できること: *将来的に関連する問題を解決してください。 * unique_ptrのデフォルトのDeleterを、デフォルトを呼び出すDeleterでオーバーライドすることが安全かどうかを確認します。

私の理解の欠如は本当に私のここに来ています。


関連の質問


  1. Friendlyは、サンプルコードではXStMachine内のフレンドとして宣言されていても、それは前方だけでなく、以前のプログラムで宣言する必要があります。なぜこれが起こるのですか?

  2. Friendlyが友人と宣言されていても、保護されたメンバー関数XStMachineにアクセスすることはできません。たとえば、&XStMachine::tranFunc1は無効です。どうして?

+3

質問全体にエラー*が発生するコードとともに、*完全なエラー出力(可能性のある情報メモを含む)が必要であることを知るには、十分な経験が必要です。 –

+0

問題のエラーを引き起こすコードは、私の質問の[本文にリンクされています](http://coliru.stacked-crooked.com/a/791092c7ca8fff24)で十分でない理由がありますか?私はもっ​​と詳細なエラー出力を共有しますが、私は本当に多くをカットしていません。念押し有難う。 – batbrat

+0

@batbrat _ "それは十分ではない何らかの理由がありますか?" _はい、あなたの質問は自己完結型である必要があります。コードが長すぎる場合は、エラーを再現する[MCVE]に絞り込みます。 –

答えて

3

std::functionは、テンプレート引数として通常の関数型のみをとります。メンバ関数へのポインタ型は機能しません。以下は

標準ライブラリにstd::functionの典型的な定義であるかもしれないです:

template<class> 
class function; // intentionally undefined 
template< class R, class... Args > 
class function<R(Args...)> // actual definition 

テンプレート引数は、このインスタンス化は保存できる機能の種類を決定ではなく、このインスタンス化がいかにていませんと呼ばれます。

通常の関数型ではない型のインスタンス化の試行では、不完全型が生成されます。例:どちらもよいコードで

std::function <int> incomplete; 

  • ストアstd::function<void(EventData const&)>マップで(ポインタ・ツー・メンバ関数とオブジェクトポインタからこれらのオブジェクトを構築するstd::bindを使用)。または
  • をすべて削除して、std::functionを完全に削除し、マップに直接ポインターのメンバー関数を格納します。
+0

テンプレートパラメータを変更すると、実際には「不完全型」の問題が解決されます。あなたの提案をstd :: bindと組み合わせると、@ pergyのstd :: bindを使う提案が私の問題を解決しました。編集:私はあなたが同じを提案したことを見た。ありがとう! – batbrat

+0

'std :: function'はあなたが言ったように宣言されているので、呼び出し可能な特殊化のみがインスタンス化されます。これは、私が正しく理解していれば、呼び出し可能な「概念」に違反していないことを保証します。 – batbrat

+0

この定義にはどのような問題がありますか? *なぜ* std :: functionが必要なのか理解していますか?目的を果たす方法でそれをどう定義しますか? –

関連する問題