简介

Substitution Failed Is Not An Error,之前笔记介绍过。这里介绍一个拓展的应用,foo 函数传入可调用对象和对应的参数,之后会判定是否可以传入对应的参数,并返回函数的执行结果,具体参考代码。这是 SFINAE 一个经典应用

#include <iostream>
#include <type_traits>
#include <utility>
#include <string>// 获取 Fn 调用 Args 的结果,std::invoke_result 可以针对 std::function,但是不可以针对 lambda
// 这里是针对任何可调用对象
template<typename Fn, typename ...Args>
using ResultOf = decltype(std::declval<Fn>()(std::declval<Args>()...));template<typename Fn, typename ...Args>
struct CallWithArgs {template<typename T, typename = void>static constexpr std::false_type Check(...) {return std::false_type{};}template<typename T, typename = ResultOf<Fn, Args...>>static constexpr std::true_type Check(std::nullptr_t) {return std::true_type{};}using IsCallable = decltype(Check<Fn>(nullptr));using RetType = std::enable_if_t<std::is_same_v<IsCallable, std::true_type>, ResultOf<Fn, Args...>>;
};template<typename Fn, typename ...Args>
std::enable_if_t<CallWithArgs<Fn, Args...>::IsCallable::value, typename CallWithArgs<Fn, Args...>::RetType>
foo(Fn &&f, Args &&...args) {return std::forward<Fn>(f)(std::forward<Args>(args)...);
}auto F = [](int n) {return std::string("hello world!") + " " + std::to_string(n);
};int f(int n) { return 10 * n; }struct Callable {std::string operator()(int n) {std::string tmp;for (int i = 0; i < n; ++i) {tmp += "test-";}return tmp;}
};int main() {std::cout << foo(F, 10) << std::endl;std::cout << foo(f, 10) << std::endl;Callable c;std::cout << foo(c, 3) << std::endl;// foo(c, "test");  // 错误,无法匹配return 0;
}

进一步拓展,返回值同样可以作为模板:

#include <type_traits>template<typename Fn, typename ...Args>
using ResultOf = decltype(std::declval<Fn>()(std::declval<Args>()...));template<typename Fn, typename ...Args>
struct CallWithArgs {template<typename T, typename = void>static constexpr std::false_type Check(...) {return std::false_type{};}template<typename T, typename = ResultOf<Fn, Args...>>static constexpr std::true_type Check(std::nullptr_t) {return std::true_type{};}using IsCallable = decltype(Check<Fn>(nullptr));using RetType = std::enable_if_t<std::is_same_v<IsCallable, std::true_type>, ResultOf<Fn, Args...>>;
};template<typename T>
class Future;template<typename T>
struct IsFuture : std::false_type {using Inner = T;
};template<typename T>
struct IsFuture<Future<T>> : std::true_type {using Inner = T;
};template<typename Fn, typename ...Args>
typename CallWithArgs<Fn, Args...>::RetType foo(Fn &fn, Args &&...args) {using RetType = typename CallWithArgs<Fn, Args...>::RetType;if constexpr (IsFuture<RetType>::value) {  // future<T> 的返回值类型} else {}return std::forward<Fn>(fn)(std::forward<Args>(args)...);
}template<typename Fn, typename ...Args>
typename CallWithArgs<Fn, Args...>::RetType then(Fn &fn, Args &&...args) {using RetType = typename CallWithArgs<Fn, Args...>::RetType;if constexpr (IsFuture<RetType>::value) {  // future<T> 的返回值类型} else {}return std::forward<Fn>(fn)(std::forward<Args>(args)...);
}

参考文档

http://kaiyuan.me/2018/05/08/sfinae/
https://marvinsblog.net/post/2019-09-11-cpp-sfinae-intro/
https://zhuanlan.zhihu.com/p/21314708
https://izualzhy.cn/SFINAE-and-enable_if

SFINAE 应用1相关推荐

  1. 【转】C++中的SFINAE

    C++中的SFINAE 2011-05-11 15:45:20 分类: C/C++ 这几天神游到一段is_base_of的代码迷惑了很久, 在查资料的过程当中, 发现C++中一种称之为SFINAE的技 ...

  2. boost::hana::sfinae用法的测试程序

    boost::hana::sfinae用法的测试程序 实现功能 C++实现代码 实现功能 boost::hana::sfinae用法的测试程序 C++实现代码 #include <boost/h ...

  3. SFINAE and enable_if

    在C ++中将函数重载与模板混合时,必须考虑一个有趣的问题.模板的问题在于它们通常包含过多的内容,并且与重载混合使用时,结果可能令人惊讶: #include <iostream>void ...

  4. SFINAE和enable_if

    SFINAE和enable_if SFINAE SFINAE可以说是C++模板进阶的门槛之一,如果选择一个论题来测试对C++模板机制的熟悉程度,那么在我这里,首选就应当是SFINAE机制. 我们不用纠 ...

  5. C++那些事之SFINAE

    介绍c++的SFINAE概念:类成员的编译时内省 0.导语1.C++自省?2.老式的C++98方式2.1重载决议2.2 SFINAE2.3 sizeof运算符2.4 结合一切2.5 实现我们的想法2. ...

  6. 现代C++之SFINAE

    介绍c++的SFINAE概念:类成员的编译时内省 0.导语1.C++自省?2.老式的C++98方式2.1重载决议2.2 SFINAE2.3 sizeof运算符2.4 结合一切2.5 实现我们的想法2. ...

  7. C++ SFINAE简介和std::enable_if_t的简单使用

    最近整理代码时发现了有人常会使用std::enable_if_t,据说这个是C++14才支持的写法,因此再次勾起了我的整理欲.但要是熟悉std::enable_if的话其实也没啥太大难度,自认为这种使 ...

  8. Json文件解析(下

    Json文件解析(下) 代码地址:https://github.com/nlohmann/json 从STL容器转换 任何序列容器(std::array,std::vector,std::deque, ...

  9. 零基础学C++进腾讯,这份GitHub热榜的「从入门到高薪」请你收下

    贾浩楠 发自 凹非寺 量子位 报道 | 公众号 QbitAI 零基础想学C++进大厂?这件事其实没那么难. 一位国内在读研究生的C++学习指南本月初登上了Github热榜,目前已经收割2000星. 避 ...

最新文章

  1. 模板 - 二分图(包含全套常用定理性质)
  2. matlab freqz函数使用
  3. Hadoop最常用的工具(SQL on Hadoop):Hive
  4. 怎样快速掌握深度学习TensorFlow框架?
  5. mpvue微信小程序动画_入门微信小程序
  6. PostgreSQL中的执行计划
  7. 是兄弟就来砍我!“贪玩蓝月”母公司实控人被捕:曾是中国最年轻富豪
  8. 内录音频工具哪个好 怎么录制电脑音频
  9. matlab——矩阵运算
  10. Zhu-Net——一个隐写分析网络
  11. Python编程:通过百度文字识别提取表格数据
  12. php页面导出csv,使用PHP生成并导出CSV文件
  13. mac版源码编译安装mysql
  14. WPS文字绿色版下载 WPS Office 2010 中文绿色版
  15. 疯言疯语 -- 物联网与智能汽车与智慧城市
  16. finally、catch和return,你真的会用吗?
  17. 人工智能教程 - 1.1.1 什么是神经网络
  18. 如何在浏览器里面将/u53f0/u6e7e/u7701转换为汉字
  19. 关于使用MethodHandle在子类中调用祖父类重写方法的探究
  20. 有没有好奇过,用浏览器访问某个网站时,中间经历了什么,如何到达对方的?(初学版)

热门文章

  1. python queue 生产者 消费者_生产者、消费者模型---Queue类
  2. max转obj_工程动画制作 | Max插件Multiscatter进阶教程
  3. 【TensorFlow-windows】(一)实现Softmax Regression进行手写数字识别(mnist)
  4. Android studio 去除软件运行时顶部原有的蓝色/绿色框
  5. 实验3.2 定义一个简单的Computer类
  6. 《南溪的目标检测学习笔记》——COCO数据集的学习笔记
  7. 我为啥不想用Python
  8. 给定随机数列求第k大的数字
  9. 实现Fragment在ViewPager中滑动
  10. 【100题】第十三题(输出倒数第k个节点)