c++ - 通用 `Is_enabled` SFINAE 结构

标签 c++ templates sfinae

我的目标是实现一个结构模板,该模板可用于检测模板替换是否格式正确或是否会失败。一个用法示例是根据模板参数是否具有可比性来提供两个版本的模板函数。

如果明确为每个场景提供结构,则可以很容易地解决这个问题,例如模板类型是否存在相等运算符,如图here .但是我未能实现一个可以接受(几乎)任意构造作为模板参数的结构。

到目前为止,我所达到的“最佳”方法是使用模板模板参数。它可以编译,但不适合参数替换应该格式正确的情况。

#include <iostream>
#include <type_traits>

template <typename T = void, typename...>
using Enable = T;

template <bool Cond, typename T = void>
using Enable_if = typename std::enable_if<Cond, T>::type;

template <typename T, template<typename> class X, typename = void>
struct Is_enabled : std::false_type {};

template <typename T, template<typename> class X>
struct Is_enabled<T, X, Enable<X<T>>> : std::true_type {};

/// An example of construct
template <typename T>
using Equals = decltype(std::declval<T>() == std::declval<T>());

template <typename T>
using Enabled_eq = Enable_if<Is_enabled<T, Equals>::value>;

template <typename T>
using Disabled_eq = Enable_if<!Is_enabled<T, Equals>::value>;

template <typename T>
Enabled_eq<T> foo()
{
    std::cerr << "enabled!" << std::endl;
}

template <typename T>
Disabled_eq<T> foo()
{
    std::cerr << "disabled!" << std::endl;
}

struct A {};

int main(int /*argc*/, const char* /*argv*/[])
{
    foo<int>();  /// should print "enabled!"
    foo<A>();    /// should print "disabled!"
    return 0;
}

int 的情况下,它显然应该打印 "enabled!",在 A 的情况下,它应该打印 "已禁用!”。但它总是打印 "disabled!",因此 Is_enabled 的特化从未完成。

我是否接近正确的解决方案,还是会更复杂?

最佳答案

Is_enabled的第三个模板参数默认为 void .这是编译器将在 Is_enabled<T, Equals> 中使用的内容实例化。即 Is_enabled<T, X, Enable<X<T>>> : std::true_type {};只能在 Enable<X<T>> 时使用评估为 void .通过显式传递模板参数 X<T>到类模板 Enable声明为:

template <typename T = void, typename...>
using Enable = T;

您实际上为 X<T> 创建了一个别名本身,以及 void类型(默认类型,调度工作所需)根本不使用。在你的情况下,X<T>decltype 的结果说明符。对于 foo<A>()它确实会导致实例化失败。对于 foo<int>() ,但是,您得到整数比较的结果类型是 bool .也就是说,虽然没有替换失败,但编译器不能使用类模板特化,因为它专用于 void。 , 不是 bool .

为了修复代码,你应该重写Enable始终以 void 结果:

template <typename...>
using Enable = void;

这也称为 std::void_t .

关于c++ - 通用 `Is_enabled` SFINAE 结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56508181/

相关文章:

c++ - < : cannot begin a template argument list

c# - 是否有基于 T4 旁边的模板生成 Razor View (.cshtml) 的方法?

c++ - 数据类型为 : float, float4、float8、double、double4、int、int4、int8 的模板

c++ - 如何实现 "either nested type or void"特征?

c++ - 从 HDC 句柄创建 QPaintDevice

c++ - 双链表类上的迭代器

c++ - 检测图像中的区域。 QT 中的重叠小部件可能吗?

c++ - 如何在openCV中将彩色图像转换为灰度图像?

c++ - 如何使用 SFINAE 调度到模板化调用运算符(operator)

c++ - 声明用于日志记录的类的模块名称