C++ 中仅返回类型不同的重载函数模板

Fed*_*dor 16 c++ templates language-lawyer overload-resolution c++20

众所周知,仅返回类型不同的普通函数不能在 C++ 中重载。

但这个限制不适用于重载的函数模板,例如:

int f(auto) { return 1; }
auto f(auto) { return 2; }
Run Code Online (Sandbox Code Playgroud)

所有编译器都接受它,演示: https: //gcc.godbolt.org/z/qj73Mzehd

为什么该语言对模板做出这样的例外?

如果重载函数的返回类型不同,则可以使用强制转换为预期函数类型来选择其中一个函数。令人惊讶的是,即使返回类型实际上相同,Clang 也允许解决歧义,例如:

((int(*)(int))f)(3);
Run Code Online (Sandbox Code Playgroud)

选择

int f(auto) { return 1; }
Run Code Online (Sandbox Code Playgroud)

演示: https: //gcc.godbolt.org/z/snfvbq1ME

Clang这里错了吗?

Sto*_*ica 12

\n

为什么该语言对模板做出这样的例外?

\n
\n

你是这个意思?

\n
\n

签名 [defns.signature.templ]

\n

\xe2\x9f\xa8function template\xe2\x9f\xa9 名称、参数类型列表、封闭命名空间(如果有)、返回类型、模板头和尾随的 require 子句(如果有)

\n
\n

是的,返回类型就在那里。这总是让诸如此类的事情成为可能

\n
template<typename T>\ntypename std::enable_if<std::is_integral<T>::value>::type foo(T&);\n\ntemplate<typename T>\ntypename std::enable_if<!std::is_integral<T>::value>::type foo(T&);\n
Run Code Online (Sandbox Code Playgroud)\n

SFINAE 是返回类型包含在签名中的原因。返回类型中可能会出现替换失败,因此它是签名比较的一部分。您仍然可能生成两个冲突的专业化来重载(在一般情况下,不在示例中),但模板会有所不同。

\n

  • SFINAE 是原因还是副作用?允许 `template &lt;typename T&gt; T Make();`... (2认同)