解决外部库缺乏常量正确性的问题
Work around lacking const-correctness of external library
我正在使用缺乏常量正确性的外部 C++ 库。假设我正在处理以下 class:
的对象
// Library.h
namespace Library {
class Message {
public:
std::string getData() {
return data_;
}
private:
std::string data_;
};
} // namespace Library
请注意,getData()
returns 是一个副本,因此对该方法的调用不会更改 Message
对象,它应该是 const
。但是,供应商决定不这样做。
在我这边的代码中,const 正确性很重要,Message
将在这样的函数中使用:
// MyApplication.cpp
template<class T>
void handleMessage(const T& msg) {
std::string content = msg.getData();
// interprete and process content ...
}
有办法实现吗?换句话说,如何解决 error: passing 'const Library::Message' as 'this' argument discards qualifiers
错误 而无需 更改 handleMessage
函数的签名?
你基本上有两个选择。您可以使用 const_cast
template<class T>
void handleMessage(const T& msg) {
std::string content = const_cast<T&>(msg).getData();
// interprete and process content ...
}
这很好,只要您确定 getData
确实没有修改任何成员。或者,如果您不介意一些开销,您可以复制一份:
template<class T>
void handleMessage(const T& msg) {
T copy = msg;
std::string content = copy.getData();
// interprete and process content ...
}
... 或者作为第三个选项,如果你想从调用站点隐藏 const_cast
,你可以将它包装起来:
class MyMessage {
Message msg;
public:
std::string getData() const {
return const_cast<Message>(msg).getData();
}
};
您还可以将包装器与可变成员变量一起使用,例如:
#include <string>
class Message {
public:
std::string getData() {
return data_;
}
Message(std::string data): data_{data} { }
private:
std::string data_;
};
class MessageWrapper {
public:
MessageWrapper(Message message): message{message} {}
std::string getData() const {
return message.getData();
}
private:
mutable Message message;
};
template<class T>
void handleMessage(const T& msg) {
std::string content = msg.getData();
}
int main() {
MessageWrapper mw{{"abc"}};
handleMessage(mw);
}
编辑:
要强制 const 正确性,您可以保存一次从消息中检索到的数据,例如:
#include <string>
#include <optional>
class Message {
public:
std::string getData() {
return data_;
}
Message(std::string data): data_{data} { }
private:
std::string data_;
};
class MessageWrapper {
public:
MessageWrapper(Message message): message{message} {}
std::string getData() const {
return (data)?(*data):(*(data = message.getData()));
}
private:
mutable Message message;
mutable std::optional<std::string> data;
};
template<class T>
void handleMessage(const T& msg) {
std::string content = msg.getData();
}
int main() {
MessageWrapper mw{{"abc"}};
handleMessage(mw);
}
我正在使用缺乏常量正确性的外部 C++ 库。假设我正在处理以下 class:
的对象// Library.h
namespace Library {
class Message {
public:
std::string getData() {
return data_;
}
private:
std::string data_;
};
} // namespace Library
请注意,getData()
returns 是一个副本,因此对该方法的调用不会更改 Message
对象,它应该是 const
。但是,供应商决定不这样做。
在我这边的代码中,const 正确性很重要,Message
将在这样的函数中使用:
// MyApplication.cpp
template<class T>
void handleMessage(const T& msg) {
std::string content = msg.getData();
// interprete and process content ...
}
有办法实现吗?换句话说,如何解决 error: passing 'const Library::Message' as 'this' argument discards qualifiers
错误 而无需 更改 handleMessage
函数的签名?
你基本上有两个选择。您可以使用 const_cast
template<class T>
void handleMessage(const T& msg) {
std::string content = const_cast<T&>(msg).getData();
// interprete and process content ...
}
这很好,只要您确定 getData
确实没有修改任何成员。或者,如果您不介意一些开销,您可以复制一份:
template<class T>
void handleMessage(const T& msg) {
T copy = msg;
std::string content = copy.getData();
// interprete and process content ...
}
... 或者作为第三个选项,如果你想从调用站点隐藏 const_cast
,你可以将它包装起来:
class MyMessage {
Message msg;
public:
std::string getData() const {
return const_cast<Message>(msg).getData();
}
};
您还可以将包装器与可变成员变量一起使用,例如:
#include <string>
class Message {
public:
std::string getData() {
return data_;
}
Message(std::string data): data_{data} { }
private:
std::string data_;
};
class MessageWrapper {
public:
MessageWrapper(Message message): message{message} {}
std::string getData() const {
return message.getData();
}
private:
mutable Message message;
};
template<class T>
void handleMessage(const T& msg) {
std::string content = msg.getData();
}
int main() {
MessageWrapper mw{{"abc"}};
handleMessage(mw);
}
编辑:
要强制 const 正确性,您可以保存一次从消息中检索到的数据,例如:
#include <string>
#include <optional>
class Message {
public:
std::string getData() {
return data_;
}
Message(std::string data): data_{data} { }
private:
std::string data_;
};
class MessageWrapper {
public:
MessageWrapper(Message message): message{message} {}
std::string getData() const {
return (data)?(*data):(*(data = message.getData()));
}
private:
mutable Message message;
mutable std::optional<std::string> data;
};
template<class T>
void handleMessage(const T& msg) {
std::string content = msg.getData();
}
int main() {
MessageWrapper mw{{"abc"}};
handleMessage(mw);
}