奇怪的解析行为 _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

在任何合理的平台上,这些都应该是二进制兼容的。