在 clang 和 gcc 中是否有视觉C++ __declspec(属性声明属性)的替代方案?
Is there an alternative for visual C++ __declspec (property declaration attribute) in clang and gcc?
有一个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;
}
有没有办法用 clang 或 gcc 定义属性声明属性? 如果我搜索__declspec
,我找到的只是__declspec(dllexport)
,但我不是在寻找那个。
虽然C++不提供对智能可覆盖运算符的支持(并且没有gcc扩展(,但该语言允许您使用其现有功能实现它。
以下示例(不假定涵盖所有情况!(显示了使用本机 C++ 11 或更高版本的可能解决方案。
我们可以使用虚拟覆盖来覆盖属性,但这不是现代智能属性在其他语言(如 swift、C# 等(中的工作方式,所以相反 - 我使用 lambda 为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;
}
编译如下:c++ -std=c++11 test.cpp -o test
运行:./test
clang 有支持
请参阅我的示例:https://godbolt.org/z/PobB_3
尽管您必须使用-fdeclspec
或-fms-extensions
将其打开
是的,
查看此链接
__declspec(property(get=..,put=..))
完全由clang支持,这是gcc中对此Microsoft语言功能的支持的延续。
我一直在叮当声中使用它;它非常适合封装和重构。我帮助调试和推广了正确的clang实现。
它在优化数组访问器属性方面做得很好。
foo[expr0][expr1] = expr2;
foo
在哪里
__declspec(property(put=foo_set)) foo_t foo[];
foo_t foo_set(T0 expr0, T1 expr1, foo_t expr2) {..}
它还与模板化函数配合使用,使其成为高效重载和前向引用的理想选择。
template<typename T0, typename T1, typename foo_ta = foo_t>
foo_ta foo_set(T0 expr0, T1 expr1, foo_ta expr2) {..}
唯一遗憾的是,您不能使用以下现代 c++自定义属性速记:
[[msvc::property(put = foo_set)]] foo_t foo[];
所以我使用这个模式:
[[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) {..}
或
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
}
您不需要使用我上面显示的任何模板用法或数组访问器用法。我提供它只是为了说明属性和利用重载函数可以做什么。
我使用-Wattributes
控制有关[[msvc::...]]
未定义的警告。有了这种模式,我的代码既为未来做好了准备,又可以干净、更一致地读取。
给定属性仅适用于实例。将它们放置在类型上的技术是在类型上使用空的单例:
struct T {
static inline struct K {
..declare properties on `k` here..
} k;
.. whatever you are doing with this `T` type.
};
现在,您可以按以下方式访问该类/静态属性:
T::k.property ..
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 {
static_assert(!WriteOnly, "Cannot access write-only property.");
// Call override getter if we have it
if (getter) return getter();
return get();
}
const T& operator = (const T& other) {
static_assert(!ReadOnly, "Cannot set read-only property.");
// 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;
};
只是对Moshe Gottlieb的回答的一个警告。虽然这确实很好用,但它并不能涵盖所有情况。如果对象被序列化然后反序列化(特别是我尝试在传递给 Cuda 内核的对象上使用它(,引用显然停止工作,并且你会得到一个损坏的对象。所以它与"__declspec(属性(得到...",在这种情况下有效。
- 警告:忽略模板参数上的属性..在 std::unique_ptr (-wignore 属性)的声明中
- 在C++/Cython中,是否可以只声明相关属性在Python中可见
- 如何在C++中用属性声明COM接口
- 在 clang 和 gcc 中是否有视觉C++ __declspec(属性声明属性)的替代方案?
- 为什么结构属性声明和初始化顺序的行为是这样的?
- 应用于类型别名声明的 [[maybe_unused]] 属性的语法
- 兼容的声明 __attribute__ ((节( ".abc.dfe" ))) 常量易失性 uint8 属性变量 = 0;- 符合MISRA标准
- C 1Z标准如何定义模板功能声明中属性的正确位置
- 通过"a pointer of the base class"访问未在基类中声明的子类的方法或属性(动态)
- 默认声明的属性?(状态设计模式)
- 声明仅在C 中使用读取属性的接口
- 如何声明 noexcept 如果只有属性的成员函数是 noexcept
- 为什么 boost::qi 规则的属性必须用括号声明?
- 通过参考或指针声明属性C
- C++属性声明
- 类中变量的属性似乎未声明
- 在可疑的情况下发出叮当警告:函数'foo'可以用属性"noreturn"声明吗?
- 警告:忽略"int scanf(const char*, ...)"的返回值,使用属性 warn_unused_result [-Wunused-result] 声明
- 在具有C++中另一个类类型的类中声明属性
- CodeSynthesis XSD CXX 不解析 XML 文件,表示未声明属性/元素