是否可以为std :: array定义隐式转换运算符?

时间:2013-08-27 08:11:41

标签: c++ c++11 implicit-conversion

我正在尝试使用可以隐式转换为std::array的C ++类。转换有效,但并非隐含。

#include <array>

class A {
private:
    std::array<float, 7> data;
public:
    operator std::array<float, 7>&() { return data; }
    operator const std::array<float, 7>&() const { return data; }
};

int main() {
    A a;
    a[1] = 0.5f; // fails to compile
    auto it = a.begin(); // fails to compile
    A b;
    static_cast<std::array<float, 7>>(b)[1] = 0.5f; //ok
    auto it2 = static_cast<std::array<float, 7>>(b).begin(); //ok
    return 0;
}

我理解上面的例子很复杂,因为它基本上完全暴露了类的private成员。但这是一个过于简单的例子,我只是想解决为什么隐含转换到std::array不起作用的问题。

我已经使用clang-3.2gcc-4.8尝试了上述示例。都没有编译。

更令人困惑的是,如果我使用隐式转换到指针,编译显然会成功:

operator float *() { return data.begin(); }
operator const float *() const { return data.cbegin(); }

但当然,这意味着失去std::array的许多细节,如果没有更好的解决方案,我会接受。

2 个答案:

答案 0 :(得分:3)

您可以通过在operator[]上重载begin()A,或者从array公开继承(不推荐)来让他们工作。

隐式转换仅在有意义时才会起作用(例如,如果您将A传递给期望std::array<float, 7>的函数),而不是在您的情况下。如果你问我,这是件好事。

答案 1 :(得分:3)

我正在通过评论回答你的问题:

  

请您详细说明为什么我的转换没有意义?在尝试解析operator []时,为什么编译器不考虑可能的转换?

简短的回答,因为它是如何运作的。可以在此处调用内置类型的转换运算符,而不是用户定义的类型。

更长的答案:

在表达式中使用运算符时,重载决策遵循13.3.1.2中规定的规则。

首先:

  

2如果任一操作数的类型是类或枚举,则用户定义的操作符函数可能是   声明实现此运算符或用户定义的转换可能是转换操作数所必需的   到适合内置运算符的类型。在这种情况下,使用重载决策来确定   调用哪个运算符函数或内置运算符来实现运算符[...]。

为此目的,

a[1]被解释为a.operator[](1),如同一部分的Table 11所示。

然后按如下方式执行查找:

  

3对于带有cv-unquali fi ed版本为T1的类型的操作数的一元运算符@和对于二进制运算符   operator @,左侧操作数的类型,其cv-unquali fi ed版本为T1,右操作数为类型   其cv-unquali fi ed版本为T2,三组候选函数,指定成员候选者,非   成员候选人和内置候选人的构建如下:

     
    

- 如果T1是一个完整的类类型,那么候选成员集就是合格查找的结果     T1 :: operator @(13.3.1.1.1);否则,成员候选人是空的。的 [1]

         

- 非成员候选者集合是在上下文中对operator @进行不等式查找的结果     根据通常的不合格函数调用中的名称查找规则的表达式(3.4.2)     除了忽略所有成员函数。但是,如果没有操作数具有类类型,则只有那些类型     查找集中具有第一个T1类型参数或“引用(可能是)的非成员函数     cv-quali fi ed)T1“,T1是枚举类型,或者(如果有右操作数)第二个参数     类型T2或“引用(可能是cv-quali fi ed)T2”,当T2是枚举类型时,是候选     功能。 [2]

         

- 对于运营商,一元运算符&amp;或运算符 - >,内置候选集是空的。     对于所有其他运算符,内置候选项包括所有已定义的候选运算符函数     在13.6中,与给定的算子相比,

         
      

- 具有相同的运营商名称和
       - 接受相同数量的操作数,和
       - 接受可根据要转换给定操作数或操作数的操作数类型       13.3.3.1和 [3]
       - 与任何非模板非成员候选者没有相同的参数类型列表。

    
  

结果如下:

  • [1]找不到任何内容(您班级中没有operator[]
  • [2]什么都没找到(没有自由函数operator[],而且两个操作数都不是枚举类型)
  • [3]找到内置operator[](float*, std::ptrdiff_t),因为A声明转换为float*