Stack Overflow is garbage
Stack Overflow is garbage

Reputation: 247969

Why does MSVC fail to compile this template function?

I ran into a problem porting some code to MSVC, which puzzles me. As far as I know, the code should be legal, and Clang compiles it just fine.

I've narrowed it down to the following:

enum E {
    x
};

template <typename T>
struct traits {
    static const E val = x;
};

template <E e>
struct S {
    S(){};
};

template <typename T>
S<traits<T>::val> foo(T t);

int main() {
    char c = 0;
    foo(c);
}

Note that after compilation, the code is expected to yield a linker error (I stripped away the definition of the function foo to keep the sample minimal), but it should compile cleanly as far as I know.

However, MSVC gives me this error:

error C2893: Failed to specialize function template 'S::val> foo(T)'

So my question:

I've reproduced the problem on VC++ 2010 and 2012.

Upvotes: 12

Views: 654

Answers (1)

user1357649
user1357649

Reputation:

After running a few tests myself, this seems to be a compiler bug in MSVC. While it works fine with GCC, MSVC gives cryptic and unhelpful compiler error (identical to the ones in your question) when you attempt to use traits<T>::val inside the template parameters for the S< E e > return.

The funny thing is, when you change S< E e > to take an integer instead, it works. Consider this example, identical to yours with some different naming:

enum E {
    x
};

template <typename T>
struct traits {
    static const E val = x;
};

template <E e>
struct S {
    S(){};
};

template <typename T>
S< traits<T>::val > tricky(T t) {
    return S< traits<T>::val > ();
};

int main() {
    char thiskidwhowalksaround = 0;
    S<x> s = tricky( thiskidwhowalksaround );
}

Now, let's just change one single thing:

template <int e> // int instead of E
struct S {
    S(){};
};

The program then compiles (links, and runs) flawlessly for me. If you also revert back to the original, and then pass in a value of E directly, like:

template <typename T>
S< x > tricky(T t) { 
// ^ here
    return S< x > (); // <-- here
};

Then the program compiles file. MSVC has the issue where it bites the dust at trying to do the following:

traits<T>::val

where val is any kind of enumeration. I'm 99% certain this is a deficiency in the Compiler itself. This seems to be perfectly well-formed C++ so I can't say that GCC is doing something wrong or extension-y by having the original code snippet work. Thus, the best I can glean is that MSVC is lacking in compiler robustness compared to its peers, yet again.

You can stop reading here, because now I'm going to take a small moment to rant about the MSVC compiler.

begin<rant> It's not that the VC++ team is bad or that C++ is bad, but from what I glean the compiler team and the standard library teams at Microsoft -- as of time of writing -- are tiny compared to other departments. It irks me that such a fundamental and important language and part of the core of MS's industry has such comparatively little manpower that it cannot keep up with what - in my short lifetime - I find to be one of the slowest moving standards in the world. I certainly am not knocking the individuals that work on the VC++ team, but I'm deeply perplexed as to why there are not more of them working on bringing C++ not only up to speed but making the compiler work better and as good as its other product areas. end<rant>

Upvotes: 3

Related Questions