【问题标题】:Taking the address of an overloaded function template is possible, sometimes有时可以获取重载函数模板的地址
【发布时间】:2015-07-13 19:40:47
【问题描述】:

gcc 4.9.0:

#include <iostream>
#include <map>

struct A
{
    typedef int type;
};

template<typename T> void foo(T*) { std::cout << "a" << std::endl; }
template<typename T> void foo(typename T::type*) { std::cout << "b" << std::endl; }

template<typename T>
struct identity
{
    typedef T type;
};

template<typename T> void bar(T*) { std::cout << "a" << std::endl; }
template<typename T> void bar(typename identity<T>::type*) { std::cout << "b" << std::endl; }

int main()
{
    //auto f = foo<A>; // ambiguous
    foo<A>(0); // prints "b", as the second overload is more specific

    auto b = bar<A>; // fine
    bar<A>(0); // prints "b", as the second overload is more specific (?)
    b(0); // prints "b"

    return 0;
}

关于为什么在第二种情况下可以获取地址的任何线索?

【问题讨论】:

  • Clang 拒绝这两种情况。
  • g++ 4.9.0 似乎接受了第二个
  • @T.C., g++ 4.9.2 编译代码并生成匹配 OP 描述的输出。
  • @T.C.我认为 Clang 在这里是错误的。至少拒绝bar,拒绝foo是正确的

标签: c++ templates language-lawyer overload-resolution


【解决方案1】:

auto的扣法与模板扣法相同。来自 [dcl.spec.auto]:

当使用占位符类型声明的变量被初始化时,[...],推导的返回类型或变量类型是 由其初始化程序的类型确定。如果占位符是自动类型说明符, 推导的类型是使用模板参数推导的规则确定的。如果占位符是autotype-specifier, 推导的类型是使用模板参数推导规则确定的。

所以当我们有任何一个时:

auto f = foo<A>;
auto b = bar<A>;

我们正在执行类型推断,就好像我们调用了(借用 T.C. 的单词选择):

template <typename M> void meow(M );
meow(foo<A> );
meow(bar<A> );

并使用推导的类型M分别作为fb的类型。

但是,根据[temp.deduct.type],强调我的:

如果模板参数仅用于非推导 上下文并且没有明确指定,模板参数推导失败。

未推断的上下文是:
— [...]
— 一个函数形参,因为关联的函数而无法进行实参推导 参数是一个函数,或一组重载函数 (13.4),并且适用以下一项或多项:
多个函数匹配函数参数类型(导致二义推导), 或
— 没有函数与函数参数类型匹配,或者
— 作为参数提供的一组函数包含一个或多个函数模板。
— [...]

在这两种情况下,参数都是一组包含一个或多个函数模板的重载函数 - 这使其成为非推导上下文,因此模板参数推导失败。因此,clang 拒绝这两种初始化是正确的。

【讨论】:

  • 这很棘手。我倾向于认为 [temp.deduct.type]/5.5.1 使其成为非推断上下文,这意味着auto 的推断在这两种情况下都应该失败。
  • @gd1 有关偏序的更全面答案,请查看Columbo's answer here
  • @Barry 我不是在说bar 的扣除(显然那里没有扣除),我说的是auto 的扣除,就像你做了@987654332 @并推导出M
  • @Barry 请记住,模板参数推导发生在重载决议之前。所以首先你需要推导出M,然后使用[over.over]中的规则来选择一个重载。但是这里不能推导出M,因为你有一个重载的函数集。
  • @T.C.我们去吧。我相信这是现在的正确答案?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-03
  • 2017-05-04
相关资源
最近更新 更多