【问题标题】:Getting SFINAE correct with functions使用功能正确获取 SFINAE
【发布时间】:2014-07-24 19:58:57
【问题描述】:

我写了一个快速的东西来确定给定类型(和参数)是否可以转换为普通函数指针。它的工作原理是这样的:

template <typename F, typename...Args>                                                                                                                        
struct is_stateless : std::is_convertible<F, typename std::result_of<F(Args...)>::type (*) (Args...)>::type                                                    
{}; 

这在大多数情况下运行良好,但它有一个严重的缺点:使用std::result_of&lt;F(Args...)&gt;::type。如果你不小心为你的函数提供了错误的参数(比如你遗漏了&amp;),你会因为result_of 没有type 字段而得到模板错误。在这种情况下,我更希望我的is_stateless 结构只是“假”(如果您提供了一个“正确”的函子和碰巧不能转换为函数指针的参数,那就是这样)。

我愿意使用 GCC4.8.* 及更低版本中的 C++11 和 c++1y 功能。关于如何做到这一点的任何想法?

【问题讨论】:

  • 嗯,我想知道检查std::decay 的类型(或使用与它所做的类似的技术)是否真的可以帮助。
  • @BartekBanachewicz 不确定这会起作用 - 应该允许带有 () 运算符和 FP 转换运算符的任意类通过它。 std::decay 不会捕捉到这一点。

标签: c++ templates c++11 sfinae


【解决方案1】:

不允许实例化result_of&lt;F(Args...)&gt;,其中Args 不正确,因为F 是不允许的。如果您仍然这样做,则无法从错误中恢复。

您可以做的是避免使用result_of:您可以使用decltype(declval&lt;F&gt;()(declval&lt;Args&gt;()...)) 获得相同的结果。这也应该适用于 SFINAE 上下文:

#include <utility>
#include <vector>

template <typename F, typename...Args>
void funcptr_helper(...);

template <typename F, typename...Args>
auto funcptr_helper(F, Args...) -> decltype(std::declval<F>()(std::declval<Args>()...));

template <typename F, typename...Args>
struct funcptr {
  typedef decltype(funcptr_helper<F, Args...>(std::declval<F>(), std::declval<Args>()...)) (*type)(Args...);
};

template <typename F, typename...Args>
struct is_stateless : std::is_convertible<F, typename funcptr<F, Args...>::type>::type {};

int main() {
  auto f1 = [](int i){ return i; };
  static_assert(is_stateless<decltype(f1), int>::value, "");

  int j = 0;
  auto f2 = [=](int i){ return i + j; };
  static_assert(!is_stateless<decltype(f2), int>::value, "");

  static_assert(is_stateless<std::vector<int>& (*) (std::vector<int>&, int, char, bool), std::vector<int>&, int, char, bool>::value, "");
  static_assert(!is_stateless<std::vector<int>& (*) (std::vector<int>&, int, char, bool)>::value, "");
  static_assert(!is_stateless<std::vector<int>& (*) (std::vector<int>&, int, char, bool), const std::vector<int>&, int, char, bool>::value, "");
}

【讨论】:

  • 恐怕这行不通:例如,static_assert(is_stateless&lt;std::vector&lt;int&gt;&amp; (*) (std::vector&lt;int&gt;&amp;, int, char, bool), std::vector&lt;int&gt;&amp;, int, char, bool&gt;::value, "oh dear"); 返回 false。我仍然不确定错误是什么 - 有什么想法吗? @hvd
  • auto funcptr_helper(F, Args&amp;&amp;...)
  • @MatthewMilano 总体思路确实有效,我只是在funcptr_helper 的签名中缺少&amp;&amp;,导致funcptr_helper 的预期过载被拒绝。
  • @MatthewMilano 实际上,再想一想,在这里避免扣除可能更容易。已编辑。
猜你喜欢
  • 2019-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-01
  • 1970-01-01
相关资源
最近更新 更多