SFINAE 用于检测非成员模板函数的存在

2023-12-23

TL;DR我想写一个模板函数Process(T value)根据非成员函数的存在,对于不同的值表现不同CreateProcessor<T>()。我能为此做些什么呢?

我对 SFINAE 有疑问。假设我们需要支持功能CreateProcessor返回接口的实现IProcessor<T>对于某些类型类型T.

在 C++ 中,我们不能创建仅返回类型不同的函数的多个重载,因此我们必须使函数CreateProcessor也可以是参数化的模板函数T.

现在假设我们要写一个模板函数Process<T>(T value)根据是否存在而工作不同CreateProcessor<T>(),即它应该处理value使用处理器以防万一CreateProcessor<T>()已执行,否则会导致错误。

我尝试编写以下代码:

#include <cstdio>
#include <type_traits>

// A workaround for void_t as described here: http://en.cppreference.com/w/cpp/types/void_t.
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;

// An interface for a processor that receives a value of specific type.
template<class T>
class IProcessor {
public:
    virtual void process(T value) = 0;
};

// A processor for int.
class IntProcessor : public IProcessor<int> {
public:
    virtual void process(int value) override {
        printf("IntProcessor::process is called for value = %d\n", value);
    }
};

// Template prototype.
template<class T> 
IProcessor<T>* CreateProcessor();

// Template specialization for int.
template<>
IProcessor<int>* CreateProcessor() {
    return new IntProcessor();
}

// Detector of CreateProcessor.
template<class, class=void>
struct CreateProcessorImplemented : std::false_type { };

template<class T>
struct CreateProcessorImplemented<T, void_t<decltype(CreateProcessor<T>())>> : std::true_type { };


// Specializations depending on existence of CreateProcessor.
template <typename T>
typename std::enable_if<CreateProcessorImplemented<T>::value, void>::type Process(T value) {
    IProcessor<T>* processor = CreateProcessor<T>();
    processor->process(value);
}

template <typename T>
typename std::enable_if<!CreateProcessorImplemented<T>::value, void>::type Process(T value) {
    printf("Processor for requested typename is unavailable\n");
}


int main() {
    Process(42);
    Process("abc");

// static_assert(!CreateProcessorImplemented<char const*>::value, ":(");
/* This static_assert fails with an error:
 * code.cpp:56:5: error: static assertion failed: :(
 *      static_assert(!CreateProcessorImplemented<char const*>::value, ":(");
 */
}

虽然这会导致链接错误:

/tmp/ccTQRc9N.o:code.cpp:function std::enable_if<CreateProcessorImplemented<char const*, void>::value, void>::type Process<char const*>(char const*): error: undefined reference to 'IProcessor<char const*>* CreateProcessor<char const*>()'
collect2: error: ld returned 1 exit status

我的想法是,当我们解决CreateProcessorImplemented<char const*>, decltype(CreateProcessor<const char*>())不会失败,因为有模板原型IProcessor<T> CreateProcessor()并且编译器认为 decltype 等于IProcessor<T>这在某种程度上是合乎逻辑的,但不是我需要的。


使其工作的一种方法是使用包装结构来运行CreateProcessor像这样:

#include <cstdio>
#include <type_traits>

// A workaround for void_t as described here: http://en.cppreference.com/w/cpp/types/void_t.
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;

// An interface for a processor that receives a value of specific type.
template<class T>
class IProcessor {
public:
    virtual void process(T value) = 0;
};

// A processor for int.
class IntProcessor : public IProcessor<int> {
public:
    virtual void process(int value) override {
        printf("IntProcessor::process is called for value = %d\n", value);
    }
};

// Template prototype.
template<class T>
struct ProcessorCreator: std::false_type { 
   static IProcessor<T>* CreateProcessor();
};

// Template specialization for int.
template<>
struct ProcessorCreator<int>: std::true_type {
static IProcessor<int>* CreateProcessor() {
    return new IntProcessor();
}
};

// Detector of CreateProcessor.
template<class, class=void>
struct CreateProcessorImplemented : std::false_type { };

template<class T>
struct CreateProcessorImplemented<T, typename std::enable_if<ProcessorCreator<T>::value>::type > : std::true_type { };


// Specializations depending on existence of CreateProcessor.
template <typename T>
typename std::enable_if<CreateProcessorImplemented<T>::value, void>::type Process(T value) {
    IProcessor<T>* processor = ProcessorCreator<T>::CreateProcessor();
    processor->process(value);
}

template <typename T>
typename std::enable_if<!CreateProcessorImplemented<T>::value, void>::type Process(T value) {
    printf("Processor for requested typename is unavailable\n");
}


int main() {
    Process(42);
    Process("abc");

// static_assert(!CreateProcessorImplemented<char const*>::value, ":(");
/* This static_assert fails with an error:
 * code.cpp:56:5: error: static assertion failed: :(
 *      static_assert(!CreateProcessorImplemented<char const*>::value, ":(");
 */
}

或者,您可以删除模板声明并使用函数重载传递 IProcessor 模板参数类型 - 通过创建虚拟参数:

#include <cstdio>
#include <type_traits>

// A workaround for void_t as described here: http://en.cppreference.com/w/cpp/types/void_t.
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;

// An interface for a processor that receives a value of specific type.
template<class T>
class IProcessor {
public:
    virtual void process(T value) = 0;
};

// A processor for int.
class IntProcessor : public IProcessor<int> {
public:
    virtual void process(int value) override {
        printf("IntProcessor::process is called for value = %d\n", value);
    }
};


IProcessor<int>* CreateProcessor(const int&) {
    return new IntProcessor();
}

// Detector of CreateProcessor.
template<class, class=void>
struct CreateProcessorImplemented : std::false_type { };

template<class T>
struct CreateProcessorImplemented<T, void_t<decltype(CreateProcessor(std::declval<T>()))>> : std::true_type { };


// Specializations depending on existence of CreateProcessor.
template <typename T>
typename std::enable_if<CreateProcessorImplemented<T>::value, void>::type Process(T value) {
    IProcessor<T>* processor = CreateProcessor(value);
    processor->process(value);
}

template <typename T>
typename std::enable_if<!CreateProcessorImplemented<T>::value, void>::type Process(T value) {
    printf("Processor for requested typename is unavailable\n");
}


int main() {
    Process(42);
    Process("abc");

// static_assert(!CreateProcessorImplemented<char const*>::value, ":(");
/* This static_assert fails with an error:
 * code.cpp:56:5: error: static assertion failed: :(
 *      static_assert(!CreateProcessorImplemented<char const*>::value, ":(");
 */
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SFINAE 用于检测非成员模板函数的存在 的相关文章

随机推荐

  • 加密:使用初始化向量还是密钥?

    我正在使用 PHPmcrypt图书馆和AES 256 rijndael 算法 需要密钥 初始化向量才能运行 我的逻辑头脑并不真正同意这一点 难道只有一把钥匙就够了吗 理论场景 如果我将加密的敏感数据存储在数据库中 只有所有者才能解密 那么使
  • 如何在 RxJs 5 中将主题转换为可观察对象

    我们如何在 RxJs 5 中将主题转换为可观察对象 例如 当我们想要公开主题进行订阅但又不想放弃对调用的控制时 此功能非常有用next 并倾向于将新值的发布保密 文档 参见here https github com Reactive Ext
  • oracle查询出错单行子查询返回多行

    知道这里有什么问题吗 如何将以下 Sybase 查询转换为 Oracle Sybase查询 Update student s1 set s1 delay select date1 date2 from cource c where c ID
  • C# WPF 在 Stackpanel 中编程创建的 DataTemplate Dockpanel 没有效果

    我正在尝试为列表框动态创建数据模板 这是针对自定义用户控件的 这个用户控件有一个依赖属性它接受任何类型的IEnumerable 这工作正常 但输出总是 适当的价值 适当的价值 如果对象包含 2 个属性 但我希望这些属性并排排列 喜欢 对象1
  • 增加 R for Mac 中的内存限制

    我一直在查看网上发布的有关如何增加 R 内存限制的解决方案 但这些解决方案似乎只适用于windows https stackoverflow com questions 1395229 increasing or decreasing th
  • Codeigniter:CSS 文件中的 base_url() 不起作用

    base url 不适用于 CSS 文件 这是我的 php 这是我的 css style css body background 356aa0 url
  • WindowsFormsHost 中的 MouseWheel 事件

    我有一个 WPF 应用程序 它使用 WindowsFormsHost 控件来托管 Windows Forms 控件 我尝试实现 MouseWheel 事件 但似乎 MouseWheel 事件从未触发 这个问题有解决方法吗 解决方法是使用事件
  • 极值的 logit 和逆 logit 函数

    我需要 logit 和逆 logit 函数 以便logit inv logit n n 我使用 numpy 这是我所拥有的 import numpy as np def logit p return np log p np log 1 p
  • CKEditor 去除内联属性

    我使用 CKEditor 一段时间了 效果很好 我几乎已经摆脱了我遇到的任何问题 但这个问题我似乎无法弄清楚 例如 当我向元素添加内联属性时style color ff0 on a p p 当我从所见即所得视图切换到源视图时 它们的标签被删
  • 使用 wget 和 Windows Scheduler 运行 php 脚本

    在我的笔记本电脑上 我安装了一个网络服务器并编写了一个脚本 通过访问脚本http localhost test search php在任何浏览器中都可以使其正常运行 它搜索 下载和存储某些推文 我现在想让脚本每20分钟自动运行一次 所以我下
  • 使用 java lambda 调用 kotlin 函数时,Kotlin 无法访问 kotlin.jvm.functions.Function1

    我正在尝试从 Java 调用以下 Kotlin 函数 override fun First list LinqList
  • 在离散 x 轴上绘制 geom_vline

    我无法在绘图的 x 轴上以离散 因子 水平绘制垂直线 在这个解决方案中 它似乎有效在ggplot2中绘制具有因子水平的垂直线 https stackoverflow com questions 50534862 drawing vertic
  • OpenApiGenerator - 如何跳过由于版本更改而生成文件更改

    我正在使用typescript rxjs发电机 每当我生成 API 客户端的新版本时 所有文件都会发生更改 其中 99 是因为版本更改 The version of the OpenAPI document 1 47 0 rc 20 真正的
  • 这个宏有什么作用? __success(返回 >= 0) 长

    在Windows头文件WinNT h中 HRESULT定义如下 typedef success return gt 0 long HRESULT 做了一些研究 我了解到 success 宏是微软源代码注释语言的一部分SAL并定义在sal h
  • Facebook 登录问题无法获取用户的实际 Facebook ID

    我们有一个适用于 Android iOS 和 Web 的应用程序 该应用程序使用facebook登录 使用easyfacebook jar http www easyfacebookandroidsdk com download asp 作
  • 如何解决?假设程序集引用'System.Web.Mvc

    参考问题 26393157 windows update caused mvc3 and mvc4 stop working https stackoverflow com questions 26393157 windows update
  • Yii 可排序属性

    我有以下表 但是当我将名字定义为可排序时 它不起作用 没有将名字显示为链接 我可以在其中单击并对列表视图进行排序 尽管如此 如果我的用户名工作得很好 User userid username Profile userid firstname
  • 通用类型扩展联合不会被类型保护缩小

    我尝试复制安德斯的条件类型和泛型示例 他在2018年建造 https channel9 msdn com Events Build 2018 BRK2150 36 45 他使用条件类型作为返回类型来替代更传统的函数重载 该幻灯片有以下内容
  • IIS 10 应用程序池睡着了

    我们有内部使用的 ASP NET Core 应用程序 该应用程序在办公时间使用 并且有一批应在每天凌晨 3 点处理 计划由HangFire像这样 RecurringJob AddOrUpdate gt MyBatch 0 0 3 1 1 问
  • SFINAE 用于检测非成员模板函数的存在

    TL DR我想写一个模板函数Process T value 根据非成员函数的存在 对于不同的值表现不同CreateProcessor