如果全部启用,则启用
Version >= C++ 11
励志的例子
在模板参数列表中有可变参数模板包时,如下面的代码片段所示:
template<typename ...Args> void func(Args &&...args) { //... };
标准库(在 C++ 17 之前)没有直接的方法来编写 enable_if 来对 Args
中的所有参数或 Args
中的任何参数施加 SFINAE 约束。C++ 17 提供了 std::conjunction
和 std::disjunction
来解决这个问题。例如:
/// C++17: SFINAE constraints on all of the parameters in Args.
template<typename ...Args,
std::enable_if_t<std::conjunction_v<custom_conditions_v<Args>...>>* = nullptr>
void func(Args &&...args) { //... };
/// C++17: SFINAE constraints on any of the parameters in Args.
template<typename ...Args,
std::enable_if_t<std::disjunction_v<custom_conditions_v<Args>...>>* = nullptr>
void func(Args &&...args) { //... };
如果你没有可用的 C++ 17,有几种解决方案可以实现这些目标。其中之一是使用基本案例类和部分特化,如本问题的答案所示。
或者,也可以用相当直接的方式手工实现 std::conjunction
和 std::disjunction
的行为。在下面的例子中,我将演示实现并将它们与 std::enable_if
组合以产生两个别名:enable_if_all
和 enable_if_any
,它们完全按照它们的语义进行操作。这可以提供更具伸缩性的解决方案。
**** enable_if_all
和 enable_if_any
的实施
首先让我们分别使用自定义的 seq_and
和 seq_or
来模拟 std::conjunction
和 std::disjunction
:
/// Helper for prior to C++14.
template<bool B, class T, class F >
using conditional_t = typename std::conditional<B,T,F>::type;
/// Emulate C++17 std::conjunction.
template<bool...> struct seq_or: std::false_type {};
template<bool...> struct seq_and: std::true_type {};
template<bool B1, bool... Bs>
struct seq_or<B1,Bs...>:
conditional_t<B1,std::true_type,seq_or<Bs...>> {};
template<bool B1, bool... Bs>
struct seq_and<B1,Bs...>:
conditional_t<B1,seq_and<Bs...>,std::false_type> {};
然后实现非常简单:
template<bool... Bs>
using enable_if_any = std::enable_if<seq_or<Bs...>::value>;
template<bool... Bs>
using enable_if_all = std::enable_if<seq_and<Bs...>::value>;
最后一些助手:
template<bool... Bs>
using enable_if_any_t = typename enable_if_any<Bs...>::type;
template<bool... Bs>
using enable_if_all_t = typename enable_if_all<Bs...>::type;
用法
用法也很简单:
/// SFINAE constraints on all of the parameters in Args.
template<typename ...Args,
enable_if_all_t<custom_conditions_v<Args>...>* = nullptr>
void func(Args &&...args) { //... };
/// SFINAE constraints on any of the parameters in Args.
template<typename ...Args,
enable_if_any_t<custom_conditions_v<Args>...>* = nullptr>
void func(Args &&...args) { //... };