如何在类中存储指向字符串到成员函数映射的智能指针,以便它不会因类型不完整而失败?



背景


我一直在编写一个在运行时加载过渡表的statemachine。进行每个过渡的动作作为字符串存储。字符串转换为指向状态计算机类的成员函数的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处理不完整类型之间的区别的信息。我尝试了一个共享的_ptr,但这也无法解决我的问题。

  4. 我尝试在状态机上创建一个friend类,以期到朋友班的声明时,该类型将被视为完整。我无法工作。

  5. 最后,我创建了以下最小示例(请重现错误的毫头代码。给专家!:)


源代码


#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;
           ^~~~~~~~

目标


primary :了解示例代码中正在发生的事情并修复它。

次要:明确了解什么是不完整的类型,以便我可以: *将来解决相关问题。 *知道是否安全地使用deleter来覆盖unique_ptr的默认deleter,该deleter调用默认值。

我缺乏理解确实在这里妨碍了我。


相关问题


  1. 即使Friendly在示例代码中的XStMachine中被声明为朋友,也必须在程序中较早地声明它。为什么会发生?

  2. 即使Friendly被声明为朋友,它也无法访问XStMachine的受保护成员功能。例如,&XStMachine::tranFunc1无效。为什么?

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,然后直接在地图中存储指针到会员功能。

相关内容

  • 没有找到相关文章

最新更新