使用和重载基类的模板成员函数
using and overloading a template member function of a base class?
在下面,结构Y
重载X
的成员函数f
。这两个重载都是模板函数,但采用不同的参数(typename
和int
),以明确指定:
struct X
{
template <typename> static bool f() { return true; }
};
struct Y : public X
{
using X::f;
template <int> static bool f() { return false; }
};
int main()
{
std::cout << Y::f <void>() << " " << Y::f <0>() << std::endl;
}
这将使用 gcc 打印1 0
,如预期的那样。然而,叮当(3.3)抱怨
[...] error: no matching function for call to 'f'
std::cout << Y::f <void>() << " " << Y::f <0>() << std::endl;
^~~~~~~~~~~
[...] note: candidate template ignored: invalid explicitly-specified argument
for 1st template parameter
template <int> static bool f() { return false; }
^
即只能看到Y
的版本。我试过了
using X::template f;
相反,没有成功。非静态(模板)成员函数也会发生同样的情况。那么这是一个错误吗?
这个难题最近根据另一个答案向我解释了。
从 #clang IRC 频道:
[01:16:23] <zygoloid> Xeo: this is a weird corner of the language where clang conforms but the rule is silly
[01:16:31] <Xeo> ... really? :(
[01:16:45] <zygoloid> Xeo: when deciding whether a using-declaration is hidden, we're not allowed to look at the template-parameter-list (nor the return type, iirc)
[01:17:04] <zygoloid> so the derived class declaration of operator()(T) suppresses the using-declaration
[01:17:19] <Xeo> because it has the same signature / parameter types?
[01:17:40] <zygoloid> rigth
解决方法是不在uses
派生版本的类中定义f
。相反,将其移动到辅助帮助程序类中(在这种情况下,这引出了一个问题,您认为哪个定义应该获胜)。
请参阅此处了解我之前有问题的案例:Lambda 函数作为基类
@Xeo知道为什么 clang++ 拒绝这个:coliru.stacked-crooked.com/a/6a0e6a1cac062216(叮当:coliru.stacked-crooked.com/a/5c2d6dd449a92227)
以下是使用额外的基类修复它的方法:
无论如何@Xeo修复了它,出于某种原因,这种形式对 clang++ stackoverflow.com/a/18432618/85371 并不反感
感谢@Xeo和休息室里的人挖掘出这个"愚蠢的规则"
令人非常失望的是,这样的约束存在并且在 C++11 中没有放松(可能有充分的理由,但我无法想象为什么)。我觉得它打败了阶级等级制度的整个概念。
无论如何,这是我找到的一种解决方法。我包含了另一个非静态的函数g
来说明差异,因为这种情况是我的主要兴趣。
template <typename Y>
struct X
{
template <typename> static bool f() { return true; }
template <typename> bool g() { return true; }
template <int I>
static bool f() { return Y::template _f <I>(); }
template <int I>
bool g()
{
return static_cast <Y&>(*this).template _g <I>();
}
};
class Y : public X <Y>
{
friend class X <Y>;
template <int> static bool _f() { return false; }
template <int> bool _g() { return false; }
};
int main()
{
Y y;
std::cout << Y::f <void>() << " " << Y::f <0>() << std::endl;
std::cout << y. g <void>() << " " << y. g <0>() << std::endl;
}
所以所有的重载都发生在基类X
中,它通过将Y
作为模板参数来实现静态多态性(幸运的是,在我的项目中已经是这种情况,所以我不改变设计)。
实际Y
的实现是在私有函数_f
,_g
。当有许多派生类(如 Y
类)中只有一个重载,而单个基类X
有多个其他重载时,此设计很好。在这种情况下,可以避免大量代码重复。同样,在我的项目中就是这种情况。
X
不需要知道这些函数的返回值。不幸的是,它确实需要知道返回类型:我已经尝试过例如 auto g() -> decltype(...)
,同样,这个decltype
仅适用于 gcc。启用 c++1y 只写入没有尾随返回类型规范的auto g()
,从而避免了decltype
的问题。但是,clang对"正常函数的返回类型扣除"(N3638)的支持仅在当前的SVN版本中可用。
在auto g()
成为主流(和标准)之前,必须手动计算Y
方法的返回类型,这可能会很痛苦,尤其是在有很多Y
的情况下。
对我来说,它仍然看起来一团糟,但至少不是完整的。
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 将公共但非静态的成员函数与ALGLIB集成
- 使用指向成员的指针将成员函数作为参数传递
- 将重载的成员函数传递给函数模板
- 我不小心调用了一个没有自己类对象的成员函数.但这是怎么回事呢
- 如何在C++中使用非静态成员函数作为回调函数
- C++错误C2600:无法定义编译器生成的特殊成员函数(必须首先在类中声明)
- 关联容器的下界复杂性:成员函数与非成员函数
- 在 C++ 中用派生类型重写成员函数
- 链表的泛型函数remove()与成员函数remove)
- 如何将lambda作为模板类的成员函数参数
- constexpr构造函数需要常量成员函数时出现问题
- 将自由函数绑定为类成员函数
- 区分非成员函数和头文件中的成员函数
- 如何从子成员函数修改父公共成员变量
- 保留对其他类的成员函数的引用
- 在运算符重载定义中使用成员函数(const错误)
- 内联如何影响模块接口中的成员函数
- 将成员函数指针作为参数传递给模板方法