模板_Atomic奇怪的解析行为

Strange parsing behavior _Atomic with templates

本文关键字:Atomic 模板      更新时间:2023-10-16
//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视为限定符?

关键字_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>
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));
}