【问题标题】:How does template type deduction work with an overloaded function as the parameter模板类型推导如何使用重载函数作为参数
【发布时间】:2018-01-01 01:00:20
【问题描述】:

看看这个(简化的)例子:

int foo(int) { return 0;}
double foo(double) { return 0.0; }

template <class T>
enable_if<is_integral<T>::value>
bar(T(*f)(T)) {}

int main()
{
   bar(foo);
   return 0;
}

我的期望是编译器将首先尝试为每个重载实例化模板,这将在第二次重载时失败 (SFINAE),因此候选集中只剩下 void bar(int(*f)(int),这将解决使用foo 的第一个重载。事实并非如此。它失败了,如下所示:

no matching function for call to ‘bar(<unresolved overloaded function type>)’
couldn't deduce template parameter ‘T’

有没有办法实现这样的目标?

【问题讨论】:

  • 编译器如何推断模板参数 T?当给出 'T foo(T)' 时,你怎么知道引用了哪个 'foo'?
  • @OnMyLittleDuck 随着 OP 认为它的工作方式,它会工作:编译器将尝试推断 T 用于 int foo(int) 重载,并将尝试它用于 double foo(double) 重载。然后,T = double 将导致替换错误,因此只保留T = int。现在,虽然 C++ 不能那样工作,但 OP 的猜测确实有道理。
  • stackoverflow.com/q/27523684/3002139 非常接近。至少高度相关,可能是骗人的。
  • stackoverflow.com/q/30623939/3002139 也非常接近。 OP,如果其中任何一个符合您的需求,我将很乐意锤击。
  • 我将不得不更仔细地观察它们。

标签: c++ c++17


【解决方案1】:

C++ 的类型推导非常简单。子句 [temp.deduct.call]/6.2[over.over]/1 描述了可以将重载名称用作参数的方式。

在您的示例中,两个扣除都会成功(T=intT=double),而一个替换会失败。但是语言只需要一次演绎成功。

您问如何实现它。以下是一些选项:

  1. 请勿使用重载名称、将 static_cast 转换为所需的函数类型,或在对 bar 的调用中显式提供 T 的类型。
  2. 更改重载,以便仅对其中一个重载进行扣减。换句话说,通过演绎排除重载,而不是通过替换。请参阅下面的示例。
  3. 添加另一个可以推导出T的参数。
  4. 推卸责任,避免推算 T 直到稍后。

#2 的示例:

tempate<class T> struct integral_wrapper { T t; }

integral_wrapper<int> foo(int);
double foo(double);

template<class T>
void bar(integral_wrapper<T> foo(T));

#3 的示例:

template<class T>
void bar(T (*f)(T), T);

bar(foo, 0);

#4 的示例:

struct foo_t
{
    int operator()(int);
    double operator()(double);
} foo;

template<class F>
void bar(F);

bar(foo);

请注意,通用 lambda 可以是 #4 的另一种方法。

根据您的使用情况,其中一些可能比其他更有吸引力。方法 #4 在将参数传递给 STL 算法时特别有用。

【讨论】:

    猜你喜欢
    • 2021-11-27
    • 2011-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-19
    相关资源
    最近更新 更多