Reload C ++ template functions and non-template Functions

Source: Internet
Author: User

Reload C ++ template functions and non-template Functions

Function Overloading is an important feature in C ++. Only when it comes to operator overloading, iostream, function Child, function adapter, smart pointer, and other very useful things.

Generally, in actual applications, it is either a template function or a template function overload, or a non-template function or a non-template overload. However, there are few situations where the template functions and non-template functions are reloaded.

Some time ago, in the project, we encountered a strange problem about template functions and non-template function overloading, which is probably equivalent to the following situation:

 1 template <typename T>  2 int compare(const T& lhs, const T& rhs) 3 { 4     std::cout << "template compare" << std::endl; 5     return 0; 6 } 7  8 int compare(const char* lhs, const char* rhs) 9 {10     std::cout << "ordinary compare" << std::endl;11     return 0;12 }13 14 int main(int argc, char *argv[])15 {16     char c1[] = "hello";17     char c2[] = "hello";18     compare(c1, c2);19 }

What is the final output? Hmm?

At the beginning, I took it for granted that the output was "ordinary compare", so I didn't care about it. As a result, after debugging in other parts of the program for a long time, the problem could not be found. Simply, the non-template function was changed to the partial special function of the template function, the previous problem disappears. The problem was found in the previous template function and non-template function overload. At that time, the situation was similar to the above Code.

Return to the printed results of the code output above. The output results on several mainstream compilers are as follows:

G ++ 4.8.1: template compare

Clang 3.4.2: template compare

Vs2010: ordinary compare

Let's take a look at the procedure for reloading the template function and the non-template function in C ++:

1. Create a set of candidate functions for this function name, including:

A. Any common function with the same name as the called function.

B. Any function template is instantiated. In this example, the real parameters of the template are inferred and the real parameters of the template that match the real parameters of the function used in the call are found.

2. Determine which common functions are feasible (if any ). Each template instance in the candidate set is feasible because the real parameter inference of the template ensures that the function can be called.

3. If conversion is required for calling, sort the reliable functions according to the type of conversion. Remember that the conversions allowed by calling the template function instance are limited.

A. If only one function is available, call this function.

B. If the call has ambiguity, remove all function template instances from the viable function set.

4. Rearrange the feasible functions of the function template instance.

A. If only one function is available, call this function.

B. Otherwise, the call is meaningless.

In addition, I thought it was the output of "ordinary compare" at first ". To use arrays c1 and c2 as the parameters passed to the function as real parameters, convert them to pointers to the first element of the array, that is to say, template functions and non-template functions must be converted once before they can be fully matched. Therefore, the non-template functions should be called according to the above overload resolution rules. However, this is not the case.

This question was asked by zhihu at the time. Let's take a look at Chen Shuo's answer:

C ++'s heavy-duty resolution rules are too complicated. g ++/clang are all templates using resolve. The current templates are: int compare <char [6]> (char const (&) [6], char const (&) [6]) that is to say T = char [6], the array is not converted to a pointer. If you change "hello" to another string, it will match the normal version. If g ++/clang meets the standards, I tend to think that this is a C ++ standard bug. FYI, clang consider template is better because it's an Identity Conversion, the other is array-to-pointer: #1 clang: compareStandardConversionSubsets (Context = ..., SCS1 = ..., SCS2 = ...) at llvm-3.4.2.src/tools/clang/lib/Sema/SemaOverload. cpp: 3393 #1 0x00007ffff6cfb353 in clang: CompareStandardConversionSequences (S = ..., SCS1 = ..., SCS2 = ...) at llvm-3.4.2.src/tools/clang/lib/Sema/SemaOverload. cpp: 3469 #2 0x00007ffff6cfaeff in clang: CompareImplicitConversionSequences (S = ..., ICS1 = ..., ICS2 = ...) at llvm-3.4.2.src/tools/clang/lib/Sema/SemaOverload. cpp: 3336 #3 0x00007ffff6d0ac37 in clang: isBetterOverloadCandidate (S = ..., cand1 = ..., cand2 = ..., loc = ..., userDefinedConversion = false) at llvm-3.4.2.src/tools/clang/lib/Sema/SemaOverload. cpp: 8031 #4 0x00007ffff6d0afd1 in clang: OverloadCandidateSet: BestViableFunction (this = 0x7fffffff77a0, S = ..., loc = ..., best = @ 0x7fffffff7790: 0x7fffff7860, UserDefinedConversion = false) at llvm-3.4.2.src/tools/clang/lib/Sema/SemaOverload. cpp: 8148 #5 0x00007ffff6d12220 in clang: Sema: BuildOverloadedCallExpr (this = 0x7445e0, S = 0x781630, Fn = 0x782620, ULE = 0x782620, LParenLoc = ..., args = ..., RParenLoc = ..., execConfig = 0x0, AllowTypoCorrection = true) at llvm-3.4.2.src/tools/clang/lib/Sema/SemaOverload. cpp: 10394 #6 0x00007ffff6bceb9a in clang: Sema: ActOnCallExpr (this = 0x7445e0, S = 0x781630, Fn = 0x782620, LParenLoc = ..., argExprs = ..., RParenLoc = ..., execConfig = 0x0, IsExecConfig = false) at llvm-3.4.2.src/tools/clang/lib/Sema/SemaExpr. cpp: 4470 #7 0x00007ffff7255459 in clang: Parser: ParsePostfixExpressionSuffix (this = 0x75f6f0, LHS = ...) at llvm-3.4.2.src/tools/clang/lib/Parse/ParseExpr. cpp: 1455 #8 blocks in clang: Parser: ParseCastExpression (this = 0x75f6f0, isUnaryExpression = false, isAddressOfOperand = false, NotCastExpr = @ 0x7fffffffa59f: false, isTypeCast = clang :: parser: NotTypeCast) at llvm-3.4.2.src/tools/clang/lib/Parse/ParseExpr. cpp: 1279 #9 partition in clang: Parser: ParseCastExpression (this = 0x75f6f0, isUnaryExpression = false, isAddressOfOperand = false, isTypeCast = clang: Parser: NotTypeCast) at llvm-3.4.2.src/tools/clang/lib/Parse/ParseExpr. cpp: 419 #10 0x00007ffff7251105 in clang: Parser: ParseAssignmentExpression (this = 0x75f6f0, isTypeCast = clang: Parser: NotTypeCast) at llvm-3.4.2.src/tools/clang/lib/Parse/ParseExpr. cpp: 168 #11 0x00007ffff7250f2c in clang: Parser: ParseExpression (this = 0x75f6f0, isTypeCast = clang: Parser: NotTypeCast) at llvm-3.4.2.src/tools/clang/lib/Parse/ParseExpr. cpp: 120 #12 0x00007ffff727ba85 in clang: Parser: ParseExprStatement (this = 0x75f6f0) at llvm-3.4.2.src/tools/clang/lib/Parse/ParseStmt. cpp: 371 #13 0x00007ffff727b46b in clang: Parser: ParseStatementOrDeclarationAfterAttributes (this = 0x75f6f0, cmdts = ..., onlyStatement = false, TrailingElseLoc = 0x0, Attrs = ...) at llvm-3.4.2.src/tools/clang/lib/Parse/ParseStmt. cpp: 231 #14 0x00007ffff727abae in clang: Parser: ParseStatementOrDeclaration (this = 0x75f6f0, TS = ..., onlyStatement = false, TrailingElseLoc = 0x0) at llvm-3.4.2.src/tools/clang/lib/Parse/ParseStmt. cpp: 118 #15 0x00007ffff727d7c8 in clang: Parser: ParseCompoundStatementBody (this = 0x75f6f0, is?texpr = false) at llvm-3.4.2.src/tools/clang/lib/Parse/ParseStmt. cpp: 907 #16 0x00007ffff7283373 in clang: Parser: ParseFunctionStatementBody (this = 0x75f6f0, Decl = 0x782340, BodyScope = ...) at llvm-3.4.2.src/tools/clang/lib/Parse/ParseStmt. cpp: 2458 #17 0x00007ffff7223ada in clang: Parser: ParseFunctionDefinition (this = 0x75f6f0, D = ..., templateInfo = ..., lateParsedAttrs = 0x7fffffffb8f0) at llvm-3.4.2.src/tools/clang/lib/Parse/Parser. cpp: 1171 #18 0x00007ffff7230a62 in clang: Parser: ParseDeclGroup (this = 0x75f6f0, DS = ..., context = 0, AllowFunctionDefinitions = true, DeclEnd = 0x0, FRI = 0x0) at llvm-3.4.2.src/tools/clang/lib/Parse/ParseDecl. cpp: 1617 #19 0x00007ffff7222b6b in clang: Parser: ParseDeclOrFunctionDefInternal (this = 0x75f6f0, attrs = ..., DS = ..., AS = clang: AS_none) at llvm-3.4.2.src/tools/clang/lib/Parse/Parser. cpp: 932 #20 0x00007ffff7222c33 in clang: Parser: ParseDeclarationOrFunctionDefinition (this = 0x75f6f0, attrs = ..., DS = 0x0, AS = clang: AS_none) at llvm-3.4.2.src/tools/clang/lib/Parse/Parser. cpp: 948 #21 0x00007ffff72223bb in clang: Parser: ParseExternalDeclaration (this = 0x75f6f0, attrs = ..., DS = 0x0) at llvm-3.4.2.src/tools/clang/lib/Parse/Parser. cpp: 807 #22 0x00007ffff72218ab in clang: Parser: ParseTopLevelDecl (this = 0x75f6f0, Result = ...) at llvm-3.4.2.src/tools/clang/lib/Parse/Parser. cpp: 612 #23 0x00007ffff721e1e5 in clang: ParseAST (S = ..., printStats = false, SkipFunctionBodies = false) at llvm-3.4.2.src/tools/clang/lib/Parse/ParseAST. cpp: 144

That is to say, g ++ and clang select the matching template function because they do not convert c1 and c2 to pointers to the first element of the array, but directly match, that is, T = char [6]. VS2010 converts them to pointers pointing to the first element of the array before matching. Therefore, it selects non-template functions.

Which one is correct?

Let's take a look at the conversion rules for real parameters in the template when real parameters are inferred.

In general, real parameters are not converted to match existing instantiation. On the contrary, new instances are generated. In addition to new instantiation, the compiler only performs two conversions:

1. const conversion: functions that accept const references or const pointers can be called using non-const object references or pointers, without generating new instantiation. If a function accepts a non-reference type, const is ignored for the actual parameters of the form parameter type. That is, the same instantiation is used no matter whether a const or non-const object is passed to a function that accepts a non-reference type.

2. array or function-to-pointer conversion: If the template parameter is not of the reference type, the regular pointer conversion is applied to the real parameters of the array or function type. Array arguments are treated as pointers to their first element, and function arguments are treated as pointers to function types.

According to the real parameter conversion rules, because the real parameters of the template function are of the reference type, the array real parameters are not converted to pointers, therefore, we can infer that T = typename [n] (typename is an array type, and n is the length of an array ). In this article, the template function directly infers and matches the real parameters, that is, T = char [6], instead of converting the array into a pointer before matching the function. So what I think is correct is to match the template function. If the length of the array c1 and c2 in the text is different, the two real parameters of the template function may not be inferred, resulting in a matching failure. In this case, the non-template function should be matched.

Finally, in most cases, in actual applications, the special features of template functions and template functions should be used to replace the overload of template functions and common non-template functions, to avoid template functions from being overloaded with non-template functions, resulting in different results in different compiler environments.

(End)

  

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.