While I was writing code for my project I found a very weird situation in which my C++11 code could not be cross compiled between GCC 7.3 and MSVC 2015. The case is basically this one:
// .H file
template <typename X>
struct Outer {
X x = {};
template <typename Y>
struct Inner {
Y y = {};
Inner& operator++();
};
};
// .INL file
template <typename X>
template <typename Y>
inline Outer<X>::Inner<Y>&
Outer<X>::Inner<Y>::operator++()
{
++y;
return *this;
}
// .CPP file
#include <iostream>
int main()
{
Outer<int>::Inner<int> a;
++a;
std::cout << a.y << std::endl;
return 0;
}
GCC will not complain about the above code. But MSVC will, and the error would be:
warning C4346: 'Inner': dependent name is not a type note: prefix with
'typename' to indicate a type error C2061: syntax error: identifier
'Inner' error C2143: syntax error: missing ';' before '{' error C2447:
'{': missing function header (old-style formal list?)
As suggested by the MSVC compiler itself, writing the typename
keyword on the return type will fix the issue:
template <typename X>
template <typename Y>
inline typename Outer<X>::Inner<Y>&
Outer<X>::Inner<Y>::operator++()
{
++y;
return *this;
}
But now, quite surprisingly, GCC will not compiler anymore, and its error is:
error: non-template 'Inner' used as template
inline typename Outer<X>::Inner<Y>&
^~~~~ note: use 'Outer<X>::template Inner' to indicate that it is a template error: expected
unqualified-id at end of input
Again, as suggested by the compiler itself, I tried to add the keyword template
to the return type, and this will fix the issue for GCC:
template <typename X>
template <typename Y>
inline typename Outer<X>::template Inner<Y>&
Outer<X>::Inner<Y>::operator++()
{
++y;
return *this;
}
But this fix will now break once again the MSVC build, and the error from the compiler is:
error C2244: 'Outer<X>::Inner<Y>::operator ++': unable to match
function definition to an existing declaration note: see declaration
of 'Outer<X>::Inner<Y>::operator ++' note: definition note:
'Outer<X>::Inner<Y> &Outer<X>::Inner<Y>::operator ++(void)' note:
existing declarations note: 'Outer<X>::Inner<Y>
&Outer<X>::Inner<Y>::operator ++(void)'
This time around, I just stopped as the compiler error message is not helpful, as the reported mismatch between definition and declaration does not exist: the signatures given by the compiler itself are perfectly matching.
At this point, not knowing any better solution, I decided to just define the function inside the Inner class scope in the .H file, and that would work for both GCC and MSVC. But some questions still remain: who is right? GCC or MSVC? Or is the C++ standard that in this case is too ambiguous?
Aucun commentaire:
Enregistrer un commentaire