2017-10-18 140 views
4

考虑这样一个例子:是否使用类型别名作为函数签名的函数参数部分的类型?

#include <iostream> 
#include <vector> 

template <class, class T> 
using alias = T; 

template <template <class...> class> 
struct tt_wrapper{}; 

template <class...> 
struct t_wrapper{}; 

struct A { 
    template <template <class...> class TT, class T> 
    void foo(alias<tt_wrapper<TT>, T>) { std::cout << "A::foo invoked" << std::endl; } 
}; 

struct B: A { 
    using A::foo; 
    template <class U, class T> 
    void foo(alias<t_wrapper<U>, T>) { std::cout << "B::foo invoked" << std::endl; } 
}; 

int main() { 
    B b; 
    b.foo<std::vector>(int{}); 
} 

根据[namespace.udecl]/15

当使用声明带来在 从基类名转换成一个派生 类范围,成员函数和成员函数模板派生类覆盖和/或隐藏成员函数和成员 具有相同名称的函数模板,参数类型列表, cv-qualification和基类中的ref-qualifier(如果有)(rath呃 比冲突)

显然,模板参数不应该涉及成员函数隐藏。然而在我们的例子中,模板参数使用别名进入签名。然而clang似乎并没有分享的感觉,别名是函数参数类型列表的一部分,并声称:

prog.cc:26:7: error: no matching member function for call to 'foo' 
    b.foo<std::vector>(int{}); 
    ~~^~~~~~~~~~~~~~~~ 
prog.cc:21:10: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'U' 
    void foo(alias<t_wrapper<U>, T>) { std::cout << "B::foo invoked" << std::endl; } 
     ^
1 error generated. 

我intensionally省略考虑的gcc,因为它涉及到的模板参数列表隐藏进程。铿锵声是对的吗?

+0

@StoryTeller我也这么认为... –

+0

是的,我明白了。我仍然坚持这个与“强烈的typedef”提案相结合的日子。 – StoryTeller

+3

我认为这应该被认为是一个标准缺陷。与前面的段落相比,它为命名空间范围函数模板指定了返回类型和模板参数在确定using声明是否使程序不合格时确实重要。 – aschepler

回答

2

A::fooB::foo具有

  • 相同的名称(foo
  • 参数类型列表(T !!!)
  • cv-限定符(未const,不易挥发)
  • REF - 限定符(无)

模板参数l ist没有被考虑在内。

基类中的方法不是虚拟的,因此隐藏而不是覆盖。

Demo事实上参数类型列表是T

+0

所以你说在考虑参数类型列表时,别名必须替换为基础类型,并且别名的附加模板参数不重要? –

+0

顺便说一句,对于[Demo](http://coliru.stacked-crooked.com/a/24a6188d15e36c3c),我不知道哪个编译器是正确的,如果有的话。 – Jarod42

+0

另一个有趣的[示例](https://wandbox.org/permlink/oNUfAUaFhKEkI6Y0)这次在第一个模板别名参数中使用sfinae ...这是否真的使相同的签名?! –