Overload resolution and arrays: which function should be called?

Consider the following program:

#include <cstddef> #include <cstdio> void f(char const*&&) { std::puts("char const*&&"); } // (1) void f(char const* const&) { std::puts("char const* const&"); } // (2) template <std::size_t N> void f(char const (&)[N]) { std::puts("char const(&)[N]"); } // (3) int main() { const char data[] = "a"; f(data); } 

Which f should be called? Why?

The latest released versions of the three compilers do not agree with the answer to this question:

  • (1) called when compiling a program using g ++ 4.5.2
  • (2) called when a program is compiled using Visual C ++ 2010 SP1
  • (3) called when compiling a program using Clang 3.0 (trunk 127530)

Do overload resolution rules know much in different C ++ 0x drafts? Or, are two of these compilers really just completely wrong? What overload is the correct overload that should be selected for the latest C ++ 0x project?

+29
c ++ arrays reference c ++ 11 overload-resolution
Mar 18 2018-11-11T00:
source share
3 answers

Firstly, the conversion sequence of all three is the same, except that for the first two there is an lvalue conversion (conversion of lvalue to rvalue), which, however, is not used to order the conversion sequences. All three are exact matches (the specification of the function template has the parameter type char const(&)[2] ).

If you 13.3.3.2p3 over the rules in 13.3.3.2p3 , you stop at this paragraph

S1 and S2 are binding bindings (8.5.3), and none of them refers to an implicit parameter of a non-static member function object declared without a ref-determinant, and S1 binds an rvalue link to an rvalue, and S2 binds an lvalue value to a link.

The conversion sequence cannot be formed if you want to bind the rvalue reference to the lvalue, the specification says in 13.3.3.1.4p3. If you look at how binding binding works on the last 8.5.3p5 pool, it will create a temporary (I think they mean temporary rvalue) type char const* from the lvalue array and bind the link to this temporary. Therefore, I think (1) better than (2) . The same applies to (1) to (3) , although we do not need this because (3) is a template, so in the tie we select (1) again.

At n3225 they changed the link binding rules so that rvalue links can bind to initializer expressions that are lvalues, as long as the link is bound to rvalue (possibly created by correctly initializing the transform earlier). This may affect Visual C ++ processing, which may not be relevant here.

I'm not sure about clang. Even if he ignores (1) , then he will fall between (2) and (3) , and he will need to select (2) , because this is not a template.




I think the last 8.5.3p5 bullet is confused because it says "Otherwise, the temporary type ..". It is unclear whether the temporary value refers as an lvalue or as an rvalue to 13.3.3.1.4p3, which means that I am not sure how the following should behave according to the exact words spec

 void f(int &); void f(int &&); int main() { int n = 0; f(n); } 

If we assume that the temporal relation is regarded as an rvalue according to Proposition 13, then we bind the rvalue ref to the rvalue in the second function and the lvalue in the first. Therefore, we will choose the second function, and then we will get the diagnosis using the last pool 8.5.3p5, because T1 and T2 are associated with the binding. If we assume that the temporary relationship is treated as an lvalue in accordance with paragraph 13, then the following will not work

 void f(int &&); int main() { f(0); } 

Because we bind the rvalue ref to the lvalue, which in accordance with clause 13 will make the function non-viable. And if we interpret “binding rvalue ref with lvalue” to refer to an initializer expression instead of the final expression associated with it, we will not accept the following

 void f(float &&); int main() { int n = 0; f(n); } 

This, however, is valid with n3225. So there seems to be some kind of confusion - I sent DR to the committee about this.

+12
Mar 18 '11 at 12:53
source share

I affirm that # 3 is a function selected by the appropriate compiler.

(1) is better than (2) because "The standard conversion sequence S1 is a better conversion sequence than the standard transformation sequence S2 if S1 and S2 are binding bindings (8.5.3) and none of them refers to implicit the object parameter is a non-static member function declared without ref-quali fi, and S1 links the rvalue link to rvalue, and S2 binds the lvalue link. "

(3) is better than both (1) and (2) because it is an identity transformation (others are exact correspondence conversions) and "The standard transformation sequence S1 is a better transformation sequence than the standard transformation sequence S2 if S1 is the correct subsequence S2 ( comparison of conversion sequences in canonical form defined in 13.3.3.1.1, excluding any Lvalue transformation, an identity conversion sequence is considered a subsequence of any sequence non-identity identity) "

A template against a non-template is considered only when no conversion is better "or, if not the one ..."

strange enough, although Como prefers (2) over (3). This test case does not compile:

 #include <cstddef> #include <cstdio> // (1) removed because Comeau doesn't support rvalue-references yet char f(char const* const&) { std::puts("char const* const&"); return 0; } // (2) template <std::size_t N> int f(char const (&)[N]) { std::puts("char const(&)[N]"); return 0; } // (3) int main() { const char data[] = "a"; switch (0) { case sizeof(char): break; case sizeof(f(data)): break; } } 
+4
Mar 18 '11 at 3:16
source share

This is a community wiki response for collecting excerpts from the standard (draft 3225).

Section 13.3.3 "Best Viable Function" [over.match.best]

  • Define ICSi (F) as follows:

    • if F is a static member function, ICS1 (F) is defined so that ICS1 (F) is neither better nor worse than ICS1 (G) for any function G and, symmetrically, ICS1 (G) is neither better nor worse than ICS1 ( F); otherwise,

    • let ICSi (F) denote the implicit sequence of transformations that converts the ith argument into a list into the type of the ith parameter of the viable function F 13.3.3.1 defines implicit conversion sequences and 13.3.3.2 determines which means that one implicit conversion sequence is a better conversion sequence or a worse conversion sequence than another.

    Given these definitions, a viable function F1 is defined as a better function than another viable function F2 if, for all arguments, ICSi (F1) is not a worse conversion sequence than ICSi (F2), and then

    • for some argument j, ICSj (F1) is a better conversion sequence than ICSj (F2)

    or, if it is not,

    • the context is initialization by user conversion (see 8.5, 13.3.1.5 and 13.3.1.6) and the standard conversion sequence from return type F1 to destination type (i.e., the type object is initialized) is a better conversion sequence than the standard conversion sequence from return type F2 to destination type

    or, if it is not,

    • F1 is a function without a template, and F2 is a specialized function of a template

    or, if it is not,

    • F1 and F2 are specialized function template templates, and a function template for F1 is more specialized than a template for F2 in accordance with the partial ordering rules described in 14.5.6.2.
  • If there is only one viable function, which is a better function than all other viable functions, then it is selected using overload resolution; otherwise, the call is poorly formed.

Section 13.3.3.1.4 "Linking Links" [over.ics.ref]

  • When a parameter of a reference type is directly associated (8.5.3) with an argument expression, an implicit conversion sequence is an identity transformation, if the argument expression does not have a type that is a derived class, the parameter type, in which case the implicit conversion sequence is a conversion with a derived base (13.3.3.1). If the parameter is bound directly to the result of applying the conversion function to the argument-expression, the implicit conversion sequence is a user-defined sequence (13.3.3.1.2), with the second standard conversion sequence, either an identity conversion, or if the conversion function returns an object of the type that is a derived class of type parameter, a transformation with a derived base.

  • If the parameter of the reference type is not directly related to the expression of the argument, the conversion sequence is the one required to convert the argument expression to the base type of the link in accordance with 13.3.3.1. Conceptually, this conversion sequence corresponds to the initialization of copying a temporary base type with an argument expression. Any differentiation at the top level of cv-qualifation is subdivided into initialization itself and does not constitute a transformation.

Section 13.3.3.2 “Ranking of Implicit Conversion Sequences” [over.ics.rank]

  • 13.3.3.2 determines the partial ordering of implicit conversion sequences based on improvements in sequence relation and better conversion. If the implicit conversion sequence S1 is determined by these rules to be better than S2 , then it also holds that S2 is a worse conversion sequence than S1 . If the transform sequence S1 not better and worse than the transform sequence S2 , S1 and S2 be indistinguishable transform sequences.

  • When comparing the main forms of implicit conversion sequences (as defined in 13.3.3.1)

    • the standard conversion sequence (13.3.3.1.1) is a better conversion sequence than a user-defined conversion sequence or an ellipsis conversion sequence, and

    • a user conversion sequence (13.3.3.1.2) is a better conversion sequence than an ellipsis conversion sequence (13.3.3.1.3).

  • Two implicit conversion sequences of the same form are indistinguishable conversion sequences if only one of the following rules applies:

    • The standard conversion sequence S1 is a better conversion sequence than the standard conversion sequence S2 if

      • S1 is a proper subsequence of S2 (comparing the canonical transformation sequences defined in 13.3.3.1.1, excluding any Lvalue transformation, the identity transformation sequence is considered to be the subsequence of any sequence that is not an identification conversion)

      or, if it is not,

      • rank S1 better than rank S2 , or S1 and S2 have the same rank and are distinguishable by the rules in the paragraph below

      or, if it is not,

      • S1 and S2 differ only in their qualification transformations and give similar types T1 and T2 (4.4), respectively, and the cv-qualification signature of type T1 is a proper subset of the cv-qualification signature of type T2 .

      or, if it is not,

      • S1 and S2 are binding bindings (8.5.3), and none of them refers to an implicit object parameter of a non-static member function declared without ref-quali fi, and S1 links the rvalue link to rvalue and S2 links the lvalue link.
+2
Mar 18 2018-11-11T00:
source share



All Articles