可变模板中的模糊操作符[]
ambiguous operator[] in variadic template
我试图编译这个例子,其中一个可变的类模板从可变的基数继承,每个实现不同的operator[]
:
#include <iostream>
template <typename T>
struct Field {
typename T::value_type storage;
typename T::value_type &operator[](const T &c) {
return storage;
}
};
template<typename... Fields>
struct ctmap : public Field<Fields>... {
};
int main() {
struct age { typedef int value_type; };
struct last_name { typedef std::string value_type; };
ctmap<last_name, age> person;
person[last_name()] = "Smith";
person[age()] = 104;
std::cout << "Hello World!" << std::endl;
return 0;
}
当我用gcc (Debian 4.9.2-10)编译时,我得到以下错误
main.cpp: In function ‘int main()’:
main.cpp:22:23: error: request for member ‘operator[]’ is ambiguous
person[last_name()] = "Smith";
^
main.cpp:7:27: note: candidates are: typename T::value_type& Field<T>::operator[](const T&) [with T = main()::age; typename T::value_type = int]
typename T::value_type &operator[](const T &c) {
^
main.cpp:7:27: note: typename T::value_type& Field<T>::operator[](const T&) [with T = main()::last_name; typename T::value_type = std::basic_string<char>]
main.cpp:23:17: error: request for member ‘operator[]’ is ambiguous
person[age()] = 104;
^
main.cpp:7:27: note: candidates are: typename T::value_type& Field<T>::operator[](const T&) [with T = main()::age; typename T::value_type = int]
typename T::value_type &operator[](const T &c) {
^
main.cpp:7:27: note: typename T::value_type& Field<T>::operator[](const T&) [with T = main()::last_name; typename T::value_type = std::basic_string<char>]
为什么这是模棱两可的?
做你想做的事情的一种可移植的方法大致是:
template<class...Ts>
struct operator_index_inherit {};
template<class T0, class T1, class...Ts>
struct operator_index_inherit<T0, T1, Ts...>:
T0, operator_index_inherit<T1, Ts...>
{
using T0::operator[];
using operator_index_inherit<T1, Ts...>::operator[];
};
template<class T0>
struct operator_index_inherit<T0>:
T0
{
using T0::operator[];
};
:
template<class... Fields>
struct ctmap : operator_index_inherit<Field<Fields>...> {
using base = operator_index_inherit<Field<Fields>...>;
using base::operator[];
};
这里我们线性继承每个类型,using operator[]
在我们的父母。
如果我们能using Field<Fields>::operator[]...;
,我们就不必这样做了。
使用构造函数时需要注意一些(我没有注意),但您可能不需要这样做。
生活例子。
到底出了什么问题取决于我不太确定的标准细节。基本上,你是以一种复杂的方式混合了操作符、继承和重载。即使你的代码是标准兼容的(它可能是也可能不是),它在某种程度上是兼容的,一些编译器死在
代码无效,gcc拒绝它是正确的(clang 3.6.0接受它-这是一个bug)。查找操作符的规则从[over.match.oper]:
开始[…]表示二进制文件操作符@,左操作数为cv不限定版本为T1的类型,右操作数为类型其cv- qualified版本为T2,三组候选函数,指定成员候选人, 非成员候选项和内置候选项的构造方法如下:—如果T1是一个完整的类类型或一个正在定义的类,则候选成员集合为
T1::operator@
(13.3.1.1.1)的限定查找结果;否则,为候选成员集合是空的。
查找成员名的规则是(因为我们查找的是ctmap<last_name,age>::operator[]
), from [class.member.lookup]:
查找C中f的集合,称为S(f,C),[…]]是计算出来的如下:
如果C包含名称f的声明,[…]
否则(即C不包含f的声明,或者结果声明集为空),S(f,C)为最初是空的。如果C有基类,计算每个直接基类子对象Bi中f的查找集,并将每个查找集S(f,Bi)依次合并为S(f,C)。
下面的步骤定义了将查找集S(f,Bi)合并到中间的S(f,C)中的结果:- - - - - -[…]
—否则,如果S(f,Bi)和S(f,C)的声明集不同,则合并是二义性的:newS(f,C)是一个查找集,具有无效的声明集和子对象集的并集。在随后的合并时,无效的声明集被认为不同于任何其他声明集。
- - - - - -[…)
基本上-我们这里有两个基类,都有一个operator[]
。两个声明集不同——因此合并是不明确的。消除歧义的方法是引入using-declaration,将所有基类成员函数引入派生类,以便初始查找集找到所有内容。
缩短你的例子:
struct A { void foo(char) { } };
struct B { void foo(int ) { } };
struct C : A, B { };
struct D : A, B {
using A::foo;
using B::foo;
};
有那个层次
C c;
c.foo(4); // error: ambiguous lookup set for foo()
D d;
d.foo('x') // OK: calls A::foo()
- 方便地对C++中的所有字符串文字进行模糊处理
- 想要检测图像中的模糊,但无法正确
- 具有可分离内核的 2D 模糊卷积
- 设置我的应用程序 API 感知并防止系统使其模糊和错误定位
- 如何组合许多连续的图像来模拟逼真的运动模糊?
- 谷歌测试编译错误 Os X:函数式转换从"int"到"internal::FloatingEq2Matcher"的模糊转换<float>
- 多重继承导致虚假的模糊虚拟函数过载
- 带boost的过载模糊性:可选,解决方法
- 为什么map有操作符[],set没有
- (C++)(Visual Studio) 将高斯模糊滤镜应用于 RGB 中的灰度图像
- 使用 gcc 的模糊函数过载分辨率.为什么?
- 使用纯 c++ 模糊图像
- 将高斯模糊应用于灰度图像
- 正确用于模糊过滤器的内核
- 二项式模糊图像过滤器将内核应用于图像
- 类X有多个默认构造函数和对重载函数的模糊调用
- 使用 OpenGL 计算着色器的朴素框模糊非常慢
- 并行化高斯模糊链
- 涉及模板化转换操作符和隐式复制构造函数的模糊性
- 可变模板中的模糊操作符[]