1

使用 MS Visual C++ 2012 版本 11.0.51106.01 更新 1:

int x()
{
   return 3;
}

template <typename Fun>
typename std::enable_if<std::is_same<Fun, int()>::value, int>::type 
MySh(Fun& f)
{ 
   return f();
}

template <typename Fun>
typename std::enable_if<std::is_same<Fun, int()>::value, int>::type 
MySh1(Fun&& f)
{ 
   return f();
}

template <typename Fun>
int MySh2(Fun&& f)
{ 
   return f();
}

调用代码:

   int res = MySh(x); // compiles and returns 3
   res = MySh1(x); // doesn't compile with error: error C2893: Failed to specialize function template 'std::enable_if<std::is_same<Fun,int(void)>::value,int>::type MySh1(Fun &&)
   res = MySh2(x); // compiles and returns 3

我还没有尝试使用其他编译器(还),但目的是让它与 Visual C++ 2012 一起使用和/或向 Microsoft 报告编译器错误。

我想确保我不会忽略一些微不足道的事情并犯下愚蠢的错误。当然,示例只是一个摘录,真正的预期用例更复杂并且与以下内容相关: Overloading on callables question

编辑: 我也对其他考虑感到困惑,例如:

   std::is_same<decltype(x), int()>::value; // true
   std::is_same<decltype(x), int(&)()>::value; //false

和:

template <typename Fun>
typename std::enable_if<std::is_same<Fun, int(&)()>::value, int>::type 
MySh1(Fun&& f)
{ 
   std::cout << typeid(f).name() << std::endl;   // prints int __cdecl(void)
   return f();
}

显然,我没有注意参数类型和参数类型之间的区别(Fun 与 f 和 x 相对)。

4

2 回答 2

2

答案在错误中,将您的声明替换为

template <typename Fun>
typename std::enable_if<std::is_same<Fun, int(&)()>::value, int>::type 
    MySh1(Fun&& f)
{ 
    return f();
}

发生这种情况是因为有模板案例的特殊处理标准<typename T> void foo(T&&);

如果您将一些参数传递给 foo,则以下内容成立(以 int 为例):

  • 通过lvalue int- Tint&
  • 通过lvalue const int-Tconst int&
  • 通过rvalue int-Tint
  • 通过rvalue const int-Tconst int

Scott Meyers 的好文章可能会更清楚地说明这一点。

于 2013-02-24T05:33:54.550 回答
2

Fun在那种情况下,A是 aFun&或 aFun const&或 a Fun&&—— &&makeFun绑定到上述 3 个引用中的任何一个(也许Fun const&&?不确定)。 &&表示类型推导上下文中的魔术引用。

您将其与 aint()而不是引用或 const 引用或 rvalue 引用进行了比较。

std::decay如果您不关心cv附加到什么和引用类型,我建议您使用Fun.

如在

template <typename Fun>
typename std::enable_if<std::is_same<typename std::decay<Fun>::type, int(*)()>::value, int>::type 

一个更好的选择可能是is_convertible

template <typename Fun>
typename std::enable_if<std::is_convertible<Fun, int(*)()>::value, int>::type 

这允许[]()->intlambdas 有资格成为一个可用的Fun. 但为什么要停在那里?

template <typename Fun>
typename std::enable_if<std::is_convertible<decltype(std::declval<Fun>()()), int>::value>::type 

接受任何类型Fun,使得 的实例Funoperator()应用返回可转换为的类型int

您甚至可以使用其中之一走得更远:

template <typename Fun>
auto MySh_Alpha(Fun&& f)->decltype( f() )
{ 
  return f();
}

template <typename Fun>
decltype( std::declval<Fun>()() ) MySh_Alpha2(Fun&& f)
{ 
  return f();
}

它们是等效的,并表示返回与传入的MySh_Alpha任何内容相同的类型。f

于 2013-02-24T06:21:35.150 回答