2013-04-06 47 views
11

我试图实现向量like和像[]运算符类的映射。但是我收到了编译器(g ++和clang ++)的错误消息。发现只有当类也有转换运算符为整数类型时才会发生。“运算符[]'”的模糊过载如果转换运算符到int存在

现在我有两个问题。首先是我不知道为什么编译器无法区分[](const std :: string &)和何时该类有转换运算符来输入。 第二...我需要转换和索引运算符。有谁知道如何解决这个问题?

在此先感谢和我最诚挚的问候

作品:

#include <stdint.h> 
#include <string> 

struct Foo 
{ 
    Foo& operator[](const std::string &foo) {} 
    Foo& operator[](size_t index) {} 
}; 

int main() 
{ 
    Foo f; 
    f["foo"]; 
    f[2]; 
} 

不起作用:

#include <stdint.h> 
#include <string> 

struct Foo 
{ 
    operator uint32_t() {} 
    Foo& operator[](const std::string &foo) {} 
    Foo& operator[](size_t index) {} 
}; 

int main() 
{ 
    Foo f; 
    f["foo"]; 
    f[2]; 
} 

编译器错误:

main.cpp: In function 'int main()': 
main.cpp:14:9: error: ambiguous overload for 'operator[]' in 'f["foo"]' 
main.cpp:14:9: note: candidates are: 
main.cpp:14:9: note: operator[](long int, const char*) <built-in> 
main.cpp:7:7: note: Foo& Foo::operator[](const string&) 
main.cpp:8:7: note: Foo& Foo::operator[](size_t) <near match> 
main.cpp:8:7: note: no known conversion for argument 1 from 'const char [4]' to 'size_t {aka long unsigned int}' 
+0

有没有这样的事情作为“演员操作员”。有问题的运营商是**转换**。强制转换是您在源代码中编写的内容,以告知编译器进行转换。 – 2013-04-06 18:46:00

+0

谢谢@Pete Becker指出这一点。 – r2p2 2013-04-06 18:57:59

回答

18

的问题是,你的班上有一个转换运营商uint32_t,所以编译器不知道是否要:

  1. 构建从字符串字面一个std::string并调用您的重载接受一个std::string;
  2. Foo对象转换为uint32_t,并将其用作字符串文字的索引。

虽然选项2听起来可能令人困惑,认为下面的表达式在C++中的法律:

1["foo"]; 

这是因为如何内置运营商标定义。每一段中的C++ 11标准的8.3.4/6:

Except where it has been declared for a class (13.5.5), the subscript operator [] is interpreted in such a way that E1[E2] is identical to *((E1)+(E2)) . Because of the conversion rules that apply to +, if E1 is an array and E2 an integer, then E1[E2] refers to the E2 -th member of E1 . Therefore, despite its asymmetric appearance, subscripting is a commutative operation.

因此,上面的表达式1["foo"]相当于"foo"[1],其评估对o。要解决歧义,既可以使转换操作符explicit(在C++ 11):

struct Foo 
{ 
    explicit operator uint32_t() { /* ... */ } 
// ^^^^^^^^ 
}; 

或者你可以离开这个转换操作符,因为它是,并且明确地构建std::string对象:

f[std::string("foo")]; 
// ^^^^^^^^^^^^ ^

struct Foo 
{ 
    operator uint32_t() { /* ... */ } 
    Foo& operator[](const std::string &foo) { /* ... */ } 
    Foo& operator[](size_t index) { /* ... */ } 
    Foo& operator[](const char* foo) { /* ... */ } 
    //    ^^^^^^^^^^^ 
}; 
012:

或者,可以(因为它不需要用户定义的转换)添加一个接受const char*下标操作符,这将是比任何上述的更好的匹配的一个进一步过载

另请注意,您的函数有一个非void返回类型,但目前错过return声明。这会在您的程序中注入未定义的行为

+0

现在我的大脑受伤了。但我想我现在明白了。希望使用户尽可能简单。显式转换为int或std :: string对此没有帮助。让我有点难过。 谢谢你解释和解决方案。 – r2p2 2013-04-06 12:49:39

+0

@ R2P2:我明白你的意思,而是一个'explicit'投地'uint_32'并不坏。毕竟,它会阻止像'Foo f; if(f){/ * ... * /};'或'Foo f; std :: cout <<(f + f);'从编译。 – 2013-04-06 12:52:33

+0

@ R2P2:另请注意,在我的最后一次更新,我建议进一步的替代(使用接受'为const char *'额外的过载)。 – 2013-04-06 12:53:24

2

的问题是,f["foo"]可以解析为:

  1. 转换"foo"std::string(无论是s),并做f[s]调用Foo::operator[](const std::string&)
  2. f转换为整数,调用Foo::operator int()(即i),并使用内置的[]算子是可交换的众所周知的事实做i["foo"]

两者都有一个自定义类型转换,因此含糊不清。

简单的解决方法是添加另一个过载:

Foo& operator[](const char *foo) {} 

现在,调用f["foo"]将调用新的过载,而无需任何自定义类型转换,所以不确定性被打破。

注意:从类型char[4](类型"foo")到char*的转换被认为是微不足道的,不计算在内。

2

在其他的答案提到的,你的问题是,[]通勤默认 - a[b]相同b[a]char const*,并与你的类被转换为uint32_t这是因为char*被转换为std::string好比赛。

我在这里提供的是一种方法,当你有这种严重的问题时,即使你相信它应该被调用,超负荷仍然不会被调用,这是一种“非常有吸引力的超载”。

因此,这里是一个Foo用“极具吸引力的过载”为std::string

struct Foo 
{ 
    operator uint32_t() {return 1;} 
    Foo& lookup_by_string(const std::string &foo) { return *this; } 
    Foo& operator[](size_t index) {return *this;} 
    template< 
    typename String, 
    typename=typename std::enable_if< 
     std::is_convertible< String, std::string >::value 
    >::type 
    > Foo& operator[](String&& str) { 
    return lookup_by_string(std::forward<String>(str)); 
    } 
}; 

,我们创造功能的自由站立“的字符串查找”,然后写捕获任何类型的模板可以转换成std::string

因为它在模板operator[]内隐藏了用户定义的转换,所以在检查匹配时不会发生用户定义的转换,所以这比其他需要用户定义转换的操作(如uint32_t[char*])更受欢迎。实际上,这是一个“更具吸引力”的过载,而不是完全不匹配参数的过载。

这可能导致问题,如果您有其他重载需要一个const Bar&Bar具有转换到std::string,上述过载可能会让你大吃一惊并捕获传入Bar - 无论右值和非const变量匹配以上[]签名优于[const Bar&]

+0

我真的必须阅读那本Template Metaprogramming书。 – r2p2 2013-04-06 14:18:23