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

标签 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 的许多优点,如果没有更好的解决方案,我会接受。

最佳答案

我在评论中回答你的问题:

Could you please elaborate on why my conversion does not make sense? While trying to resolve operator[], why should the compiler not consider possible conversions?

简短的回答,因为这就是它的工作原理。可以在这里调用到内置类型的转换运算符,而不是用户定义的类型。

稍微长一点的回答:

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

首先:

2 If either operand has a type that is a class or an enumeration, a user-defined operator function might be declared that implements this operator or a user-defined conversion can be necessary to convert the operand to a type that is appropriate for a built-in operator. In this case, overload resolution is used to determine which operator function or built-in operator is to be invoked to implement the operator [...].

a[1] 为此目的解释为 a.operator[](1),如 表 11 中所示相同的部分。

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

3 For a unary operator @ with an operand of a type whose cv-unqualified version is T1, and for a binary operator @ with a left operand of a type whose cv-unqualified version is T1 and a right operand of a type whose cv-unqualified version is T2, three sets of candidate functions, designated member candidates, non- member candidates and built-in candidates, are constructed as follows:

— If T1 is a complete class type, the set of member candidates is the result of the qualified lookup of T1::operator@ (13.3.1.1.1); otherwise, the set of member candidates is empty. [1]

— The set of non-member candidates is the result of the unqualified lookup of operator@ in the context of the expression according to the usual rules for name lookup in unqualified function calls (3.4.2) except that all member functions are ignored. However, if no operand has a class type, only those non-member functions in the lookup set that have a first parameter of type T1 or “reference to (possibly cv-qualified) T1”, when T1 is an enumeration type, or (if there is a right operand) a second parameter of type T2 or “reference to (possibly cv-qualified) T2”, when T2 is an enumeration type, are candidate functions. [2]

— For the operator ,, the unary operator &, or the operator ->, the built-in candidates set is empty. For all other operators, the built-in candidates include all of the candidate operator functions defined in 13.6 that, compared to the given operator,

— have the same operator name, and
— accept the same number of operands, and
— accept operand types to which the given operand or operands can be converted according to 13.3.3.1, and [3]
— do not have the same parameter-type-list as any non-template non-member candidate.

结果如下:

  • [1] 什么也没找到(你的类中没有operator[]
  • [2] 什么都找不到(没有自由函数 operator[] 并且两个操作数都不是枚举类型)
  • [3] 找到内置的 operator[](float*, std::ptrdiff_t) 因为 A 声明了一个转换为 float *

关于c++ - 是否可以为 std::array 定义隐式转换运算符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18460289/

相关文章:

c++ - 获取模板实例化的类型?

c++ - unique_ptr 住在哪里?

c++ - 为什么推导出这里的类型是uint32_t呢?

c++ - CRTP 中 shared_ptr 的隐式向下转换

c++ - 使用 istream/ostream 传输消息的类似网络协议(protocol)

c++ - Lambda函数引用指针销毁检测

c++ - 放置 new 加析构函数和简单的值初始化 noexcept 语义

c++ - `ofstream` 与 0 相比

scala - 在参数化类中混合通用特征而不重复类型参数

c++ - 使用从 1 到 N 模板参数的数字初始化 std 数组