奇怪的解析行为 _Atomic 与模板
Strange parsing behavior _Atomic with templates
//clang 3.8.0
#include <iostream>
template<typename T>
_Atomic T* get_atomic(T* val) {
return reinterpret_cast<_Atomic T*>(val);
}
int main()
{
volatile int val = 1;
_Atomic volatile int* val_ptr = reinterpret_cast<_Atomic volatile int*>(&val);
// works as expected
std::cout << *val_ptr;
// Fails due to "_Atomic cannot be applied to qualified type 'volatile int'"
//std::cout << "Hello, world!\n" << *get_atomic(&val);
}
为什么模板扩展的解析方式和显式扩展的解析方式不一致?它们应该是相同的。有没有办法确保在存在模板参数的情况下将 _Atomic 视为限定符?
这似乎是规范或 clang 中的错误。要解决它,您可以使用以下技巧来恢复原始类型的限定符:
//clang 3.8.0
#include <iostream>
template<typename T>
struct Impl {
T __a_value;
using underlying_t = T;
Impl(T val) : __a_value(val) {}
};
template <typename Tp_, typename Original_>
struct __annotate_with_qualifiers {
using __const_qualified = typename std::conditional<std::is_const<Original_>::value, const Tp_, Tp_>::type;
using __type = typename std::conditional<std::is_volatile<Original_>::value, volatile __const_qualified, __const_qualified>::type;
};
template<typename _Tp>
_LIBCPP_INLINE_VISIBILITY inline
typename __annotate_with_qualifiers<_Atomic(typename _Tp::underlying_t), _Tp>::__type*
__cxx_atomic_pointer_to_data(_Tp* __value) {
return reinterpret_cast<typename __annotate_with_qualifiers<_Atomic(typename _Tp::underlying_t), _Tp>::__type*>(&__value->__a_value);
}
template<typename T>
void print_val(const volatile T* val) {
std::cout << "Const volatile " << *val << std::endl;
}
template<typename T>
void print_val(const T* val) {
std::cout << "Const " << *val << std::endl;
}
template<typename T>
void print_val(volatile T* val) {
std::cout << "Volatile " << *val << std::endl;
}
template<typename T>
void print_val(T* val) {
std::cout << "Plain " << *val << std::endl;
}
int main()
{
Impl<int> val(1);
volatile Impl<int> val2(2);
const Impl<int> val3(3);
const volatile Impl<int> val4(4);
print_val(__cxx_atomic_pointer_to_data(&val));
print_val(__cxx_atomic_pointer_to_data(&val2));
print_val(__cxx_atomic_pointer_to_data(&val3));
print_val(__cxx_atomic_pointer_to_data(&val4));
}
关键字_Atomic
来自C (C11),不是C++中的关键字。在 C++ 中,原子是通过 std::atomic
指定的。最好不要混淆两种语言的句法概念。
如果你必须混合访问两种语言的原子数据的代码,你应该处理原子类型,例如std::atomic_int
,或者发明一些类似于下面的宏接口
#ifdef __cplusplus
#define myAtomic(T) std::atomic< T >
#else
#define myAtomic(T) _Atomic(T)
#endif
在任何合理的平台上,这些都应该是二进制兼容的。
//clang 3.8.0
#include <iostream>
template<typename T>
_Atomic T* get_atomic(T* val) {
return reinterpret_cast<_Atomic T*>(val);
}
int main()
{
volatile int val = 1;
_Atomic volatile int* val_ptr = reinterpret_cast<_Atomic volatile int*>(&val);
// works as expected
std::cout << *val_ptr;
// Fails due to "_Atomic cannot be applied to qualified type 'volatile int'"
//std::cout << "Hello, world!\n" << *get_atomic(&val);
}
为什么模板扩展的解析方式和显式扩展的解析方式不一致?它们应该是相同的。有没有办法确保在存在模板参数的情况下将 _Atomic 视为限定符?
这似乎是规范或 clang 中的错误。要解决它,您可以使用以下技巧来恢复原始类型的限定符:
//clang 3.8.0
#include <iostream>
template<typename T>
struct Impl {
T __a_value;
using underlying_t = T;
Impl(T val) : __a_value(val) {}
};
template <typename Tp_, typename Original_>
struct __annotate_with_qualifiers {
using __const_qualified = typename std::conditional<std::is_const<Original_>::value, const Tp_, Tp_>::type;
using __type = typename std::conditional<std::is_volatile<Original_>::value, volatile __const_qualified, __const_qualified>::type;
};
template<typename _Tp>
_LIBCPP_INLINE_VISIBILITY inline
typename __annotate_with_qualifiers<_Atomic(typename _Tp::underlying_t), _Tp>::__type*
__cxx_atomic_pointer_to_data(_Tp* __value) {
return reinterpret_cast<typename __annotate_with_qualifiers<_Atomic(typename _Tp::underlying_t), _Tp>::__type*>(&__value->__a_value);
}
template<typename T>
void print_val(const volatile T* val) {
std::cout << "Const volatile " << *val << std::endl;
}
template<typename T>
void print_val(const T* val) {
std::cout << "Const " << *val << std::endl;
}
template<typename T>
void print_val(volatile T* val) {
std::cout << "Volatile " << *val << std::endl;
}
template<typename T>
void print_val(T* val) {
std::cout << "Plain " << *val << std::endl;
}
int main()
{
Impl<int> val(1);
volatile Impl<int> val2(2);
const Impl<int> val3(3);
const volatile Impl<int> val4(4);
print_val(__cxx_atomic_pointer_to_data(&val));
print_val(__cxx_atomic_pointer_to_data(&val2));
print_val(__cxx_atomic_pointer_to_data(&val3));
print_val(__cxx_atomic_pointer_to_data(&val4));
}
关键字_Atomic
来自C (C11),不是C++中的关键字。在 C++ 中,原子是通过 std::atomic
指定的。最好不要混淆两种语言的句法概念。
如果你必须混合访问两种语言的原子数据的代码,你应该处理原子类型,例如std::atomic_int
,或者发明一些类似于下面的宏接口
#ifdef __cplusplus
#define myAtomic(T) std::atomic< T >
#else
#define myAtomic(T) _Atomic(T)
#endif
在任何合理的平台上,这些都应该是二进制兼容的。