[英]How to use std::atomic<T>::is_always_lock_free for SFINAE?
How can I use std::atomic<T>::is_always_lock_free
with SFINAE? 如何在SFINAE中使用
std::atomic<T>::is_always_lock_free
? I have a class template MyClass<T>
and I would like to switch between 2 implementations, depending on whether std::atomic<T>::is_always_lock_free
is true
. 我有一个类模板
MyClass<T>
,我想在2个实现之间切换,具体取决于std::atomic<T>::is_always_lock_free
是否为true
。 This is what I have: 这就是我所拥有的:
template<typename T, typename Enable = void>
class MyClass {
// Fallback implementation
};
template<typename T>
class MyClass<T, typename std::enable_if<std::atomic<T>::is_always_lock_free>::type> {
// Optimized implementation using std::atomic
};
Now, when I try to create an instance of MyClass<SomeCustomClass>
, I get a compiler error: 现在,当我尝试创建
MyClass<SomeCustomClass>
的实例时,我收到编译器错误:
_Atomic cannot be applied to type 'SomeCustomClass' which is not trivially copyable
_Atomic不能应用于类型'SomeCustomClass',它不是可轻易复制的
It tries to use the template specialization, but instead of using the fallback implementation, it doesn't compile at all. 它尝试使用模板特化,但不使用回退实现,它根本不编译。 Could someone kindly explain what's wrong here?
有人可以解释这里有什么问题吗? And how do I get the desired result?
我如何获得理想的结果?
You need to delay checking std::atomic<T>::is_always_lock_free
until after you know that T
is trivially copyable. 你需要推迟检查
std::atomic<T>::is_always_lock_free
直到你知道之后 T
是平凡的可复制。 Otherwise, atomic<T>
is ill-formed. 否则,
atomic<T>
是不正确的。
For that, there's std::conjunction
- which is lazy / short-circuits: 为此,有
std::conjunction
- 这是懒惰/短路:
template <typename T>
struct is_lock_free_impl
: std::integral_constant<bool, std::atomic<T>::is_always_lock_free> { };
template <typename T>
using is_lock_free = std::conjunction<
std::is_trivially_copyable<T>,
is_lock_free_impl<T>>;
Now, this trait will abort early and yield false_type
if T
isn't trivially copyable. 现在,如果
T
不是可轻易复制的,那么这个特性会提前中止并产生false_type
。 And if it is trivially copyable, then it's valid to instantiate atomic<T>
, so then we check that trait. 如果它是可以轻易复制的,那么实例化
atomic<T>
是有效的,那么我们检查这个特征。
In the expression std::atomic<T>::is_always_lock_free
the instantation of std::atomic<T>
fails (for the non-triviably copyable types), and that's not immediate context, hence the compilation fails. 在表达式
std::atomic<T>::is_always_lock_free
中, std::atomic<T>
的瞬间失败(对于不可挽回的可复制类型),并且这不是直接上下文,因此编译失败。 You need to not instantiate std::atomic<T>
in that case. 在这种情况下,您不需要实例化
std::atomic<T>
。 SFINAE would have worked here if std::atomic<T>
was legal, but std::atomic<T>::is_always_lock_free
would not be. 如果
std::atomic<T>
合法,SFINAE会在这里工作,但std::atomic<T>::is_always_lock_free
不会。
So how do I get the desired result?
那么如何获得理想的结果呢?
With a custom trait: 具有自定义特征:
#include <atomic>
#include <array>
#include <iostream>
class SomeClass { SomeClass& operator=(const SomeClass&) { return *this; } };
template<typename... T>
struct make_void { typedef void type; };
template<typename... T>
using void_t = typename make_void<T...>::type;
template<typename T, typename = void>
struct IsAlwaysLockFree
{
static constexpr bool value = false;
};
template<typename T>
struct IsAlwaysLockFree<T, void_t<typename std::enable_if<!std::is_trivially_copyable<T>::value>::type>>
{
static constexpr bool value = false;
};
template<typename T>
struct IsAlwaysLockFree<T, void_t<typename std::enable_if<std::is_trivially_copyable<T>::value>::type>>
{
static constexpr bool value = std::atomic<T>::is_always_lock_free;
};
template<typename T, typename Enable = void>
class MyClass {
// Fallback implementation
public:
MyClass(){ std::cout << "Fallback\n"; }
};
template<typename T>
class MyClass<T, typename std::enable_if<IsAlwaysLockFree<T>::value>::type> {
// Optimized implementation using std::atomic
public:
MyClass(){ std::cout << "Optimized\n"; }
};
int main()
{
MyClass<SomeClass> a;
MyClass<std::array<int, 1024>> b;
MyClass<int> c;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.