如何在 SFINAE 中使用 std::atomic<T>::is_always_lock_free?
How to use std::atomic<T>::is_always_lock_free for SFINAE?
如何将 std::atomic<T>::is_always_lock_free
与 SFINAE 一起使用?我有一个 class 模板 MyClass<T>
,我想在 2 个实现之间切换,具体取决于 std::atomic<T>::is_always_lock_free
是否为 true
。这是我的:
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
};
现在,当我尝试创建 MyClass<SomeCustomClass>
的实例时,出现编译器错误:
_Atomic cannot be applied to type 'SomeCustomClass' which is not trivially copyable
它尝试使用模板特化,但没有使用后备实现,它根本不编译。有人可以解释一下这里出了什么问题吗?我怎样才能得到想要的结果?
在表达式 std::atomic<T>::is_always_lock_free
中,std::atomic<T>
的实例化失败(对于不可平凡复制的类型),并且这不是直接上下文,因此编译失败。在这种情况下,您不需要实例化 std::atomic<T>
。如果 std::atomic<T>
合法,SFINAE 会在这里工作,但 std::atomic<T>::is_always_lock_free
不会。
So how do I get the desired result?
具有自定义特征:
#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;
}
您需要延迟检查 std::atomic<T>::is_always_lock_free
,直到 在您知道 之后 T
可以轻松复制。否则,atomic<T>
格式错误。
为此,有 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>>;
现在,如果 T
不可简单复制,此特征将提前中止并产生 false_type
。如果它 是 可平凡复制的,那么实例化 atomic<T>
是有效的,所以我们检查该特征。
如何将 std::atomic<T>::is_always_lock_free
与 SFINAE 一起使用?我有一个 class 模板 MyClass<T>
,我想在 2 个实现之间切换,具体取决于 std::atomic<T>::is_always_lock_free
是否为 true
。这是我的:
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
};
现在,当我尝试创建 MyClass<SomeCustomClass>
的实例时,出现编译器错误:
_Atomic cannot be applied to type 'SomeCustomClass' which is not trivially copyable
它尝试使用模板特化,但没有使用后备实现,它根本不编译。有人可以解释一下这里出了什么问题吗?我怎样才能得到想要的结果?
在表达式 std::atomic<T>::is_always_lock_free
中,std::atomic<T>
的实例化失败(对于不可平凡复制的类型),并且这不是直接上下文,因此编译失败。在这种情况下,您不需要实例化 std::atomic<T>
。如果 std::atomic<T>
合法,SFINAE 会在这里工作,但 std::atomic<T>::is_always_lock_free
不会。
So how do I get the desired result?
具有自定义特征:
#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;
}
您需要延迟检查 std::atomic<T>::is_always_lock_free
,直到 在您知道 之后 T
可以轻松复制。否则,atomic<T>
格式错误。
为此,有 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>>;
现在,如果 T
不可简单复制,此特征将提前中止并产生 false_type
。如果它 是 可平凡复制的,那么实例化 atomic<T>
是有效的,所以我们检查该特征。