使用std::function:帮助编译器消除歧义的重载函数解析

overloaded function resolution with std::function: helping compilers disambiguate

本文关键字:重载 函数 歧义 function std 帮助 编译器 使用      更新时间:2023-10-16

我想从一个重载的模板函数创建一个std::function。使用g++ -std=c++14编译时,我得到了一个重载解析错误。我有一个hack按摩函数模板成编译器识别的形式,但我想知道是否有更优雅的方法。下面的代码说明了错误和我的hack

#include <functional>
template <typename T>
T foo(T t) { return t; }
template <typename T>
T foo(T t1, T t2){ return t1 + t2; }
int main (){
    //error: conversion from ‘<unresolved overloaded function type>’ 
    //to non-scalar type ‘std::function<double(double)>’ requested
    std::function<double(double)> afunc = &foo<double>; 
    //my workaround to 'show' compiler which template 
    //function to instantiate 
    double (*kmfunc1)(double) = &foo<double>;
    std::function<double(double)> afunc = kmfunc1;  
}

我有两个问题

  • 期望编译器解析使用哪个模板是不合理的吗?
  • 在上述情况下,创建std::函数的最优雅的方法是什么?
#define OVERLOAD_SET(...) 
  [](auto&&...args)-> 
    decltype(__VA_ARGS__(decltype(args)(args)...)) 
  { 
    return __VA_ARGS__(decltype(args)(args)...); 
  }

创建一个对象,该对象表示其参数的完整(全局)重载集。(我使用...作为宏,不理解,在现代c++中的所有用途)

std::function<double(double)> afunc = OVERLOAD_SET(foo<double>);
std::function<double(double,double)> bfunc = OVERLOAD_SET(foo<double>);

两个都可以,

也可以
std::function<double(double)> afunc = OVERLOAD_SET(foo);
std::function<double(double,double)> bfunc = OVERLOAD_SET(foo);

当我们在它。这里的思想是将重载解析推迟到参数确定的时候。

OVERLOAD_SET(foo)编译为:

[](auto&&...args)
->decltype(foo(decltype(args)(args)...))
{
  return foo(decltype(args)(args)...);
}

是一个无状态的lambda,它返回在其参数上调用foo所做的任何事情。

  • 期望编译器解析使用哪个模板是不合理的吗?

编译器不允许根据c++语言规则解析使用哪个模板。相关的std::function构造函数是:

template< class F > 
function( F f );

并且,根据[temp. deduction .type]:

如果一个模板形参只在非推导式中使用如果没有显式指定,则模板参数推导失败。

未推断的上下文是:
- - - - - -[…]
-一个函数形参,其实参演绎不能进行,因为关联函数是一个函数,或者是一组重载函数(13.4),并且适用以下一个或多个条件:
    - 多个函数匹配函数形参类型(导致歧义演绎),或
    -没有函数匹配函数参数类型,否则
     -作为参数提供的函数集包含一个或多个函数模板。
- - - - - -[…)

因此传入&foo<double>是一个非推导的上下文,模板推导失败,因此出现编译错误。

    在上述情况下,创建std::函数的最优雅的方法是什么?

我只会使用强制转换:

std::function<double(double)> afunc = 
    static_cast<double(*)(double)>(&foo<double>);

,然后向标准委员会抱怨为什么std::function<Sig>没有一个接受Sig*的构造函数。按照你想要的顺序。