7

The following code was compiled on g++ 4.1.2 and g++ 4.4.4. Both give the results noted in the comments.

int f(const int * a)
{
   return 0;
}

template<typename A>
int f(A a)
{
   return 1;
}

int main()
{
    int x;
    // return f(&x); // returns 1
    return f((const int *)&x); // returns 0
}

It appears to boil down to a call of f(int *) resolves to f<int *>(int *) instead of the expected f(const int *). I found this shocking and completely unintuitive.

Is this a bug in g++, a dark corner of C++, or obvious for some reason I am missing? If it's not a bug, what's the theory or logic behind it? Are there any safe practices regarding this issue?

5
  • f(int) and f(const int) are identical prototypes as far as ANSI c++ compiler is concerned Commented Jun 23, 2011 at 23:37
  • 1
    Right, but f(int *) is not the same as f(const int *)/f(int const *) Commented Jun 23, 2011 at 23:39
  • Perhaps. Link: stackoverflow.com/questions/2121525/… Commented Jun 23, 2011 at 23:40
  • 2
    +1 for providing a minimal, complete example program. See sscce.org for reasons why that's a good idea. Commented Jun 23, 2011 at 23:50
  • 1
    @sehe "Perhaps"? I think you are misreading the discussion at that link. "foo(int *const a)" accepts a const-pointer-to-int. In the example here, "f(const int * a)" accepts a pointer-to-const-int. Commented Jun 24, 2011 at 0:35

2 Answers 2

8

For the instantiated template f<int *> no conversion (int *->const int *) is needed, so it's a better match - actually, it's an exact match, that would lose only against a non-templated exact match, which is what happens for the second call.

The full explanation of the "better match" rules is available at §13.3.3 of the C++ standard.

Sign up to request clarification or add additional context in comments.

Comments

4

Well, why are you calling the const version of the function "expected" in case of f(&x) call?

The argument type is int *, as you already know. So the f(int *) version of the function is a better match than f(const int *) version, because in the former the argument type matches exactly. The compiler sees the opportunity to generate f(int *) from the template and it takes that opportunity. That's just how it works in C++.

In cases when the template version is as good as the non-template one, the non-template one normally wins. But in this case, where the template version is obviously better, the template version wins.

Apparently you expected the compiler to choose the non-template version of the function. Why?

4 Comments

I expected it to win due to a trivial and implicit const conversion. It just seems sane to me that const upgrading a pointer type would always occur before considering templates. Perhaps there's an example as to why that would not be a good idea.
@Roland : No conversion > trivial conversion in overload resolution.
@Roland: imagine that you have two ways to perform an operation. It is destructive (with regard to its argument). In the const version, you therefore need to perform a copy of the argument first, which is obviously less efficient. Example: T&& operator+(T&&, T const&) is more efficient than T operator+(T const&, T const&).
In that case I agree simply because those are both templates. I simply meant that I expected implicit const conversion before considering any templates at all.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.