是否使用类型别名作为函数签名的函数参数部分的类型?
考虑这样一个例子:是否使用类型别名作为函数签名的函数参数部分的类型?
#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{});
}
当使用声明带来在 从基类名转换成一个派生 类范围,成员函数和成员函数模板派生类覆盖和/或隐藏成员函数和成员 具有相同名称的函数模板,参数类型列表, 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,因为它涉及到的模板参数列表隐藏进程。铿锵声是对的吗?
A::foo
和B::foo
具有
- 相同的名称(
foo
) - 参数类型列表(
T
!!!) - cv-限定符(未
const
,不易挥发) - REF - 限定符(无)
模板参数l ist没有被考虑在内。
基类中的方法不是虚拟的,因此隐藏而不是覆盖。
Demo事实上参数类型列表是T
。
所以你说在考虑参数类型列表时,别名必须替换为基础类型,并且别名的附加模板参数不重要? –
顺便说一句,对于[Demo](http://coliru.stacked-crooked.com/a/24a6188d15e36c3c),我不知道哪个编译器是正确的,如果有的话。 – Jarod42
另一个有趣的[示例](https://wandbox.org/permlink/oNUfAUaFhKEkI6Y0)这次在第一个模板别名参数中使用sfinae ...这是否真的使相同的签名?! –
@StoryTeller我也这么认为... –
是的,我明白了。我仍然坚持这个与“强烈的typedef”提案相结合的日子。 – StoryTeller
我认为这应该被认为是一个标准缺陷。与前面的段落相比,它为命名空间范围函数模板指定了返回类型和模板参数在确定using声明是否使程序不合格时确实重要。 – aschepler