Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The actual result of name resolution in the class template is different from the c++ 03 standard

I test the code in the c++ standard ISO/IEC 14882-03 14.6.1/9 on Xcode 4.1 and Visual Studio 2008. The outputs of the two compiler are both different from the expected result of the standard.

The code is pasted below.

#include <stdio.h>
#include <iostream>
using namespace std;

void f(char);

template <class T > void g(T t)
{
    f(1);
    f(T(1));
    f(t);
}

void f(int);
void h()
{
    g(2);
    g('a');
}

void f(int)
{
     cout << "f int" << endl;
}


void f(char)
{
    cout << "f char" << endl;
}


int main() { 
    h();  
    return 0;
}

As the description of the standard. The expected output should be

f char
f int
f int
f char
f char
f char

Build and run the code on Xcode 4.1. The output is as below. In the build settings, I tried to change the "Compiler for C/C++/Object-C" to be Apple LLVM Compiler 2.1, Gcc 4.2 and LLVM GCC 4.2. The outputs are the same.

f char
f char
f char
f char
f char
f char

Build and run the code on Microsoft Visual Studio 2008. The output is as below.

f int
f int
f int
f int
f char
f char

The description (14.6.1/9) of the standard is pasted below.

If a name does not depend on a template-parameter (as defined in 14.6.2), a declaration (or set of declara- tions) for that name shall be in scope at the point where the name appears in the template definition; the name is bound to the declaration (or declarations) found at that point and this binding is not affected by declarations that are visible at the point of instantiation. [Example:

void f(char);
template<class T> void g(T t)
{
f(1); // f(char) 
f(T(1)); // dependent 
f(t); // dependent 
dd++; // not dependent
}
void f(int);
double dd;
void h()
{
// error: declaration for dd not found
g(2); // will cause one call of f(char) followed // by two calls of f(int)
g(’a’); // will cause three calls of f(char) 

—end example]

The code is well-formed to the compilers, but the outputs are different. It would be very dangerous to port this code to different platforms.

Does somebody have the background why these compilers don't follow the standard?

Edit on 10/11/2011

Per http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#197, the example in the standard is wrong. I test the code below on Clang and Gcc.

#include <stdio.h>
#include <iostream>
using namespace std;

void f(char);

template <class T > void g(T t)
{
    f(1);
    f(T(1));
    f(t);
}

enum E{ e };

void f(E );
void h()
{
    g(e);
    g('a');
}

void f(E )
{
    cout << "f E" << endl;
}

void f(char)
{
    cout << "f char" << endl;
}

int main() { 
    h();  
    return 0;
}

The output as expected.

f char
f E
f E
f char
f char
f char

Thanks,

Jeffrey

like image 671
Jeffrey Avatar asked Oct 03 '11 03:10

Jeffrey


1 Answers

What you're running into is the fact that Visual Studio does not implement two-phase lookup. They only look up the actual name when you instantiate the template.

And Microsoft has pretty much decided at this point that they're not interested in supporting two-phase lookup.

like image 55
Nicol Bolas Avatar answered Oct 24 '22 17:10

Nicol Bolas