函数重载的顺序重要吗?

时间:2019-04-04 09:22:08

标签: c++ c++11 templates overloading declaration

我遇到了函数重载的顺序很重要的情况。 我以为原因一定是带有val1 value1 val2 value2 val3 value3 的SFINAE部分((我另外测试了没有std::enable_if的代码,仅使用模板,然后代码运行,而不管函数重载的顺序。))< / p>

我从中做了一个最小的工作例子。

此代码块有效

std::enable_if

以下内容无法编译(交换了#include <type_traits> template <bool C, typename R = void> using EnableIf = typename std::enable_if<C, R>::type; template <typename T, typename R = void> using IfIsArithmetic = EnableIf<std::is_arithmetic<T>::value, R>; template <typename S> IfIsArithmetic<S, void> Add(S const &scalar1, S const &scalar2, S &ret) { ret = scalar1 + scalar2; } template <typename S> IfIsArithmetic<S, S> Add(S const &scalar1, S const &scalar2) { S ret; Add(scalar1, scalar2, ret); return ret; } using T = float; int main(){ T a = 3.1; T b = 3.5; T c{Add(a, b)}; } 函数的实现)

Add()

编译器出现以下错误

#include <type_traits>

template <bool C, typename R = void>
using EnableIf = typename std::enable_if<C, R>::type;

template <typename T, typename R = void>
using IfIsArithmetic = EnableIf<std::is_arithmetic<T>::value, R>;

template <typename S>
IfIsArithmetic<S, S> Add(S const &scalar1, S const &scalar2)
{
 S ret;
 Add(scalar1, scalar2, ret);
 return ret;
}

template <typename S>
IfIsArithmetic<S, void> Add(S const &scalar1, S const &scalar2, S &ret)
{
 ret = scalar1 + scalar2;
}

using T = float;

int main(){
  T a = 3.1;
  T b = 3.5;
  T c{Add(a, b)};
}

似乎,即使签名未对齐,编译器也会尝试使用第一个函数重载。

也许有些人可以给我提示,此问题与C ++函数查找规则有关!

1 个答案:

答案 0 :(得分:3)

  

似乎,即使签名未对齐,编译器也会尝试使用第一个函数重载。

完全正确。

顺序很重要。

编译Add(S const &scalar1, S const &scalar2)的主体时,编译器不知道在其后将定义带有三个参数的Add()。因此,请尝试(目前)唯一已知的Add(),但参数数量不匹配。

SFINAE,模板和using都不是问题:同样,您也会遇到相同的错误

float Add (float const &scalar1, float const &scalar2)
{
 float ret;
 Add(scalar1, scalar2, ret);
 return ret;
}

void Add(float const &scalar1, float const &scalar2, float &ret)
{
 ret = scalar1 + scalar2;
}

int main(){
  float a = 3.1;
  float b = 3.5;
  float c{Add(a, b)};
}

如果您确实要在树形参数第一个之前定义两个参数Add(),则必须说在Add()的两个参数版本的定义之前,编译器应指定三个参数的版本跟随;您可以这样声明(未定义)三个参数的版本

void Add (float const &, float const &, float &);

float Add (float const &scalar1, float const &scalar2)
{
 float ret;
 Add(scalar1, scalar2, ret);
 return ret;
}

void Add(float const &scalar1, float const &scalar2, float &ret)
{
 ret = scalar1 + scalar2;
}

这在两个函数相互调用的情况下很有用。

在第二个示例中,您可以添加三个参数Add()

的声明。
template <typename S>
IfIsArithmetic<S, void> Add(S const &, S const &, S &);

在定义两个参数版本之前。

关闭主题

从C ++ 14开始,您可以使用std::enable_if_t,该定义(据我所知)与您的EnableIf完全一样。

从C ++ 17开始,您还可以使用std::is_arithmetic_v<T>代替std::is_arithmetic<T>::value