处理 std::enable_if<...中谓词的逻辑"OR">
handle logical "OR" for predicates in std::enable_if<...>
说,我的方法有这个返回类型定义(模板和方法无关,因此未显示(,这需要处理enable_if
谓词的逻辑"OR":
typename std::enable_if<{predicate_1} or {predicate_2}), void>::type>
my_method(...) { ... }
当然,它不起作用,因为一旦谓词替换中的任何一个失败,该实例将被清除。
我想到的第一个快速而肮脏的解决方案是提出一个定义,该定义评估失败的谓词以false
,例如,如下所示:
template<bool, typename T = void>
struct failed_2_false: std::false_type {};
template<typename T>
struct failed_2_false<true, T>: std::true_type {};
那么这将起作用:
typename std::enable_if<failed_2_false<{predicate_1}>::value or failed_2_false:<{predicate_2}>::value,
void>::type>
my_method(...) { ... }
所以,我的问题是: - 有什么/是否有标准 (STL( 惯用方法来处理谓词的逻辑"OR"?
假设您正在使用这样的 SFINAE 来检查类型是否具有T::bar
或T::type
,并且它们中的任何一个都应该int
:
template <typename T>
typename std::enable_if<
std::is_same<typename T::bar,int>::value ||
std::is_same<typename T::type,int>::value, void>::type asdf(){ std::cout << "0";}
template <typename T>
typename std::enable_if<
!std::is_same<typename T::bar,int>::value &&
!std::is_same<typename T::type,int>::value, void>::type asdf(){ std::cout << "1";}
这是行不通的,因为当T
既没有T::bar
又没有T::type
时,std::is_same<...>
已经无法替换。
解决方案是使用在替换时不会失败的谓词。基于这个答案,我们可以使用以下检测习惯用来检测类型是否具有某些属性:
// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf. template <typename...> using void_t = void; // Primary template handles all types not supporting the operation. template <typename, template <typename> class, typename = void_t<>> struct detect : std::false_type {}; // Specialization recognizes/validates only types supporting the archetype. template <typename T, template <typename> class Op> struct detect<T, Op, void_t<Op<T>>> : std::true_type {};
只是为了说明,检测类型是否具有T::type
:
template <typename T>
using has_type_t = typename T::type;
template <typename T>
using has_type = detect<T, has_type_t>;
要求T::type
属于某种类型只是更棘手一点:
template <typename X>
struct has_X_type_helper {
template <typename T>
using type = typename std::enable_if_t<std::is_same_v< typename T::type, X>,int>;
};
template <typename T,typename X>
using has_X_type = detect<T,has_X_type_helper<X>::template type>;
类型特征需要一些样板,我们必须为T::bar
编写相同的内容:
template <typename X>
struct has_X_bar_helper {
template <typename T>
using type = typename std::enable_if_t<std::is_same_v< typename T::bar, X>,int>;
};
template <typename T,typename X>
using has_X_bar = detect<T,has_X_bar_helper<X>::template type>;
请注意,特征has_X_type
和has_X_bar
确实使用 SFINAE,但这是一个实现细节。特征不会在替换时失败(除非它们的参数已经失败(,但它们的评估结果要么std::true_type
,要么std::false_type
。现在上述SFINAE可以通过||
和&&
来实现:
template <typename T>
typename std::enable_if<
has_X_type<T,int>::value ||
has_X_bar<T,int>::value, void>::type asdf(){ std::cout << "0";}
template <typename T>
typename std::enable_if<
!has_X_type<T,int>::value &&
!has_X_bar<T,int>::value, void>::type asdf(){ std::cout << "1";}
活生生的例子@神霹雳
PS:你所说的"快速和肮脏"并不脏。它快速,干净,并且可以完成工作。如果使用计算结果为std::true_type
或std::false_type
的谓词,则可以使用普通布尔运算符来构造更复杂的谓词。
相关文章:
- 使用std::multimap迭代器创建std::list
- 处理 std::enable_if<...中谓词的逻辑"OR">
- std::scoped_lock or std::unique_lock or std::lock_guard?
- std::vector using back(), pop_back(), push_back(), 得到'double free or corruption'错误
- 使用什么 std::可选 or std::unique_ptr
- 平息海湾合作委员会的"only available with -std=c++XX or -std=gnu++XX"警告
- std::lock_guard or std::scoped_lock?
- C++ decltype(auto) or decltype(std::<T>forward(value))?
- CString to std::string or sql::SQLString conversion - C++
- strtok or std::istringstream
- push_back or emplace_back with std::make_unique
- Pass std::max_element() or std::min_element() to function as
- std::unique_lock<std::mutex> or std::lock_guard<std::mutex>?
- std::vector: vec.data() or &vec[0]
- Using std::thread or CreateThread()?
- std::vector< std::vector<unsigned char> > or std::d eque< std::vector<unsigned cha
- std::remove_reference or std::remove_cv first?
- Std or boost atomic unsigned char[32]
- 有没有像"std::and"或"std::or"的东西?
- std::deque or std::list