[英]Is there an alternative for visual C++ __declspec (property declaration attribute) in clang and gcc?
There is a Microsoft specific extension, which makes it possible to define property getters and setters like this:有一个 Microsoft 特定的扩展,可以像这样定义属性 getter 和 setter:
// declspec_property.cpp
struct S {
int i;
void putprop(int j) {
i = j;
}
int getprop() {
return i;
}
__declspec(property(get = getprop, put = putprop)) int the_prop;
};
int main() {
S s;
s.the_prop = 5;
return s.the_prop;
}
Is there any way to define property declaration attribute with clang or gcc?有没有办法用 clang 或 gcc 定义属性声明属性? If I search for __declspec
, all I find is __declspec(dllexport)
, but I am not looking for that.如果我搜索__declspec
,我发现的只是__declspec(dllexport)
,但我不是在寻找那个。
While C++ does not offer support for smart overridable operators (and there are no gcc extensions for that), the language allows you to implement it using it's existing features.虽然 C++ 不提供对智能可覆盖运算符的支持(并且没有 gcc 扩展),但该语言允许您使用其现有功能来实现它。
The following example (which does not assume to cover all cases.) shows a possible solution using native C++ 11 or higher.以下示例(假定未涵盖所有情况。)显示了使用本机 C++ 11 或更高版本的可能解决方案。
We could use virtual overrides to override the properties, but that's not how modern smart properties work in other languages such as swift, C# etc, so instead - I'm using lambdas to inject overriding code for setters and getters.我们可以使用虚拟覆盖来覆盖属性,但这不是现代智能属性在其他语言(例如 swift、C# 等)中的工作方式,所以相反 - 我使用 lambdas 为 setter 和 getter 注入覆盖代码。
// The following is by no means a FULL solution!
#include <functional>
#include <iostream>
#include <cassert>
template<typename T>
class Property {
public:
Property(){}
operator const T& () const {
// Call override getter if we have it
if (getter) return getter();
return get();
}
const T& operator = (const T& other) {
// Call override setter if we have it
if (setter) return setter(other);
return set(other);
}
bool operator == (const T& other) const {
// Static cast makes sure our getter operator is called, so we could use overrides if those are in place
return static_cast<const T&>(*this) == other;
}
// Use this to always get without overrides, useful for use with overriding implementations
const T& get() const {
return t;
}
// Use this to always set without overrides, useful for use with overriding implementations
const T& set(const T& other) {
return t = other;
}
// Assign getter and setter to these properties
std::function<const T&()> getter;
std::function<const T&(const T&)> setter;
private:
T t;
};
// Basic usage, no override
struct Test {
Property<int> prop;
};
// Override getter and setter
struct TestWithOverride {
TestWithOverride(){
prop.setter = [&](const int& other){
std::cout << "Custom setter called" << std::endl;
return prop.set(other);
};
prop.setter = std::bind(&TestWithOverride::setProp,this,std::placeholders::_1);
prop.getter = std::bind(&TestWithOverride::getProp,this);
}
Property<int> prop;
private:
const int& getProp() const {
std::cout << "Custom getter called" << std::endl;
return prop.get();
}
const int& setProp(const int& other){
std::cout << "Custom setter called" << std::endl;
return prop.set(other);
}
};
int main(int,char**){
Test t;
TestWithOverride t1;
t.prop = 1;
assert(t.prop == 1);
t1.prop = 1;
assert(t1.prop == 1);
/*
Expected output:
1. No aborts on assertions
2. Text:
Custom setter called
Custom getter called
*/
return 0;
}
Compile with something like:用类似的东西编译:
c++ -std=c++11 test.cpp -o test
Run:跑:
./test
See my example at: https://godbolt.org/z/PobB_3请参阅我的示例: https://godbolt.org/z/PobB_3
Although you must turn it on with either -fdeclspec
or -fms-extensions
尽管您必须使用-fdeclspec
或-fms-extensions
将其打开
Yes,是的,
__declspec(property(get=..,put=..))
is fully supported by clang and that is a carryover from support in gcc for this Microsoft language feature. __declspec(property(get=..,put=..))
完全受clang支持,这是gcc中支持此 Microsoft 语言功能的结转。
I use it all the time in clang ;我一直在clang中使用它; it is fabulous for encapsulation and refactoring.它非常适合封装和重构。 I helped debug and promote the correct clang implementation.我帮助调试和推广了正确的clang实现。
It does a great job optimizing with array accessor properties .它对数组访问器属性进行了很好的优化。
foo[expr0][expr1] = expr2;
Where foo
is foo
在哪里
__declspec(property(put=foo_set)) foo_t foo[];
foo_t foo_set(T0 expr0, T1 expr1, foo_t expr2) {..}
It also works excellently with templated functions, making it ideal for efficient overloading and forward referencing.它还可以很好地与模板化函数配合使用,使其成为高效重载和前向引用的理想选择。
template<typename T0, typename T1, typename foo_ta = foo_t>
foo_ta foo_set(T0 expr0, T1 expr1, foo_ta expr2) {..}
The only bummer is that you can't use a modern c++ custom-attribute shorthand of:唯一的遗憾是您不能使用现代c++自定义属性简写:
[[msvc::property(put = foo_set)]] foo_t foo[];
So I use this pattern :所以我使用这种模式:
[[msvc::property(put = foo_set)]] __declspec(property(put = foo_set))
foo_t foo[];
template<typename T0, typename T1, typename foo_ta = foo_t>
foo_ta foo_set(T0 expr0, T1 expr1, foo_ta expr2) {..}
OR或者
template<bool fFwd=true>
bar_t bar_get() {
// reference any types declared later in your code
// template mechanics mean they will not be resolved until
// first **property** use
}
You do not need to use any of the template usage or array accessor usage I showed above.您不需要使用我上面显示的任何模板用法或数组访问器用法。 I only provided that to illustrate above and beyond what can be done with properties and making use of overloaded functions .我只是为了说明以上和之外的内容,可以使用属性和使用重载函数。
I control warnings about [[msvc::...]]
being undefined using -Wattributes
.我使用-Wattributes
控制有关[[msvc::...]]
未定义的警告。 With that pattern my code is both ready for the future, and reads cleanly and more consistently.使用这种模式,我的代码既可以为未来做好准备,又可以更清晰、更一致地阅读。
Given properties only work on instances .给定的属性仅适用于实例。 The technique to place them on types is to use an empty singleton on a type:将它们放在类型上的技术是在类型上使用空的 singleton:
struct T {
static inline struct K {
..declare properties on `k` here..
} k;
.. whatever you are doing with this `T` type.
};
Now you can access that class/static properties as:现在您可以访问该类/静态属性:
T::k.property ..
Moshe Gottlieb's excellent answer can be improved to allow for read-only or write-only properties at compile time with the following code.可以使用以下代码改进 Moshe Gottlieb 的出色答案,以在编译时允许只读或只写属性。
// Simulate Microsoft-specific extension:
// __declspec(property(get = getprop, put = putprop)) type propname
template<typename T, bool ReadOnly = false, bool WriteOnly = false>
class Property {
public:
Property(){}
operator const T& () const {
// Call override getter if we have it
if (getter) return getter();
return get();
}
const T& operator = (const T& other) {
// Call override setter if we have it
if (setter) return setter(other);
return set(other);
}
bool operator == (const T& other) const {
// Static cast makes sure our getter operator is called, so we could use overrides if those are in place
return static_cast<const T&>(*this) == other;
}
// Use this to always get without overrides, useful for use with overriding implementations
const T& get() const {
static_assert(!WriteOnly, "Cannot access write-only property.");
return t;
}
// Use this to always set without overrides, useful for use with overriding implementations
const T& set(const T& other) {
static_assert(!ReadOnly, "Cannot set read-only property.");
return t = other;
}
// Assign getter and setter to these properties
std::function<const T&()> getter;
std::function<const T&(const T&)> setter;
private:
T t;
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.