Is it possible to define an implicit conversion operator in std :: array?

I am trying to create a C ++ class that can be implicitly converted to std::array . The conversion works, but it is not implied.

 #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; } 

I understand that the above example is quite confusing, as it basically expands the private class member completely. But this is a simplified example, I'm just trying to solve the problem why implicit conversions in std::array do not work.

I tried the above example with clang-3.2 and gcc-4.8 . Neither compiles.

Even more perplexing is that if I use implicit conversion to a pointer, compilation obviously succeeds:

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

But of course, this means losing many of the intricacies of std::array , which I will accept if there is no better solution.

+4
source share
2 answers

I answer your question from the comment:

Could you tell us why my appeal does not make sense? When trying to resolve the [] operator, why does the compiler not consider possible conversions?

The short answer is, because that's how it works. Here you can call the conversion operator for the built-in type, and not for the custom type.

Longer answer:

When an operator is used in an expression, overload resolution follows the rules outlined in 13.3.1.2 .

First of all:

2 If any operand has a type that is a class or enumeration, then a user-defined operator function may be declared to implement this operator or a user-defined conversion may be required to convert the operand to a type that is suitable for the built-in operator. In this case, overload resolution is used to determine which operational function or built-in operator should be involved to implement the operator [...].

a[1] interpreted for this purpose as a.operator[](1) , as shown in Table 11 in the same section.

Then the search is performed as follows:

3 For a unary operator @ with an operand of type whose cv-unqualified version is T1, and for a binary operator @ with a left operand of type whose cv-unqualified version is T1 and a right operand of the type whose cv-unqualified version is T2, three sets of candidate The functions, nominated candidate candidates, candidate candidates and embedded candidates are structured as follows:

- If T1 is a complete type of class, the set of candidate candidates is the result of a quality search of T1 :: operator @ (13.3.1.1.1); otherwise, the set of candidate candidates is empty. [one]

- a set of non-member candidates is the result of an unqualified search for the @ operator in the context of an expression in accordance with the usual rules for finding names in unqualified function calls (3.4.2), except that all member functions are ignored. However, if none of the operands has a class type, functions that are not members in the search set that have the first parameter of type T1 or "reference to (possibly cv-quali-fi) 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 function candidates. [2]

- for the operator, the unary operator & or the operator β†’, the set of built-in candidates is empty. For all other operators, the built-in candidates include all the defined functions of the candidate operator defined in 13.6, which is compared to this operator

- have the same operator name and
- accept the same number of operands, and
- accept types of operands to which the given operand or operands can be converted in accordance with 13.3.3.1 and [3]
- do not have the same list of parameters as any non-template candidate that is not a member.

The result is as follows:

  • [1] does not find anything (there is no operator[] in your class
  • [2] does not find anything (there is no free function operator[] , and none of the operands are enumerated types)
  • [3] finds the built-in operator[](float*, std::ptrdiff_t) , because A declares the conversion to float*
+3
source

You can make them work by overloading operator[] and begin() on A , or publicly inheriting from array (not recommended).

Implicit conversion only works if it makes sense (say, if you passed A function that expects std::array<float, 7> ), and not in your case. And it’s good if you ask me.

+3
source

Source: https://habr.com/ru/post/1499089/


All Articles