2017-05-29 97 views
1

我想在C++中实现类似于C#setter的东西。这个想法是有一个类属性的枚举和相应的setter。我的代码如下所示。我将在类定义中编写实现。函数指针的静态映射

#include <string> 
#include <map> 

enum ClassProperties 
{ 
    Id, Name 
}; 

class MyClass 
{ 
public: 
    int Id; 
    std::string Name; 

    public void SetValue(ClassProperties c, std::string value){ 
      setters[c](this, value); 

    } 

private: 
    typedef void (* t_setter)(MyClass *, std::string); 

    static void set_id(MyClass * obj, std::string value) { 
     obj->Id = std::stoi(value); 
    } 
    static void set_name(MyClass * obj, std::string value) { 
     obj->Name = value; 
    } 

    static std::map<ClassProperties, t_setter> setters = {{ClassProperties:: Id, set_id}, {ClassProperties::Name, set_name}}; 


}; 

我期望这个代码选择cooresponding功能,并调用它,但我得到的最后一行

error: in-class initialization of static data member ‘std::map<ClassProperties, void (**)(MyClass*, std::basic_string<char>)> MyClass::setters’ of incomplete type 

error: could not convert ‘{{Id, MyClass::set_id}, {Name, MyClass::set_name}}’ from ‘<brace-enclosed initializer list>’ to ‘std::map<ClassProperties, void (**)(MyClass*, std::basic_string<char>)>’ 

什么我做错了错误?

+1

铛++提供了一个更直接的“错误:非const静态数据成员必须初始化脱节” – aschepler

+0

一旦你得到了这个工作,你可能想看看“指向成员函数”所以你可以使'set_id'和'set_name'成为非静态函数,可以调用为'obj.set_id(value);' –

+0

。这看起来不像C#setter。 –

回答

2

setters的初始化是错误的。你应该如下更改:

1)从类中删除主体的行:

static std::map<ClassProperties, t_setter> setters = 
    {{ClassProperties:: Id, set_id}, {ClassProperties::Name, set_name}}; 

2)添加静态成员的相应的初始化了类主体:

std::map<ClassProperties, MyClass::t_setter> MyClass::setters = { 
     { ClassProperties::Id, &MyClass::set_id }, 
     { ClassProperties::Name, &MyClass::set_name } 
}; 

除了,您必须在SetValue函数之前删除public说明符。

wandbox example

+0

非常感谢,但现在我得到 'MyClass :: setters''的多重定义# – Vahagn

+0

@Vahagn我添加了一个wandbox示例。 –

+0

@Vahagn不客气:) –