MSVC chokes in forward class template declaration - c++

MSVC fails to compile
#include <iostream>
template<int N, int = N>
struct A;
template<int, int V>
struct A{static constexpr int VALUE = V;};
int main() {
A<1> a;
std::cout << a.VALUE;
}
with (3): error C2065: 'N': unknown identifier
(10): error C2975: 'V': invalid template argument 'A', constant expression expected (roughly translated).
clang compiles it silently.
So, the question: rotten code or demented MSVC?
MSVC version = VS 2019.

It was a bug in MSVC manifested up to compiler version 19.22, and fixed in 19.23. Demo: https://gcc.godbolt.org/z/occvKEfc3

Related

How to use Folding Expression to initialize an array?

I come across with a weird problem in which MSVC doesn't let me to use fold expression to initialize an array in the following:
#include <iostream>
template <typename T, std::size_t ...dims>
class Matrix {
public:
void print()
{
std::cout << (... + dims) << '\n';
}
T matrix[(... + dims)]; // <-- error C2059: syntax error: '...'
};
int main()
{
Matrix<int, 3, 3, 3> m;
m.print();
Matrix<int, 3, 2, 1> n;
n.print();
return 0;
}
Here is the errors:
(10): error C2059: syntax error: '...' (11): note: see
reference to class template instantiation 'Matrix' being
compiled (10): error C2238: unexpected token(s) preceding ';'
I tried GCC and everything just worked perfectly fine!
Is there any workaround to use fold expression directly to initialize an array with MSVC?
Thank you so much guys!
This looks like a bug in the MS compiler. As with any bug of such kind, it's hard to tell what exactly goes wrong unless you know MS compiler internals.
A workaround is the introduction of an intermediate member variable:
template<typename T, std::size_t... dims>
class Matrix {
// ...
static constexpr std::size_t my_size = (... + dims);
T matrix[my_size];
};
or a static member function:
static constexpr std::size_t my_size() { return (... + dims); }
T matrix[my_size()];

Template c++ compiler differences VC++ different output

I had written some c++ code in Visual Studio and was trying to run it on my c++ code on a linux server. When I tried to compile it with G++ however, it failed to compile with tons of errors. I looked through the error and was able to simplify the problem to this:
template<int x>
struct Struct
{
template<int y>
static void F()
{
//Struct<x>::F<0>(); // compiles
//Struct<y>::G(); // compiles
Struct<y>::F<0>(); // does not compile?
}
static void G()
{
}
};
int main ()
{
Struct<0>::F<0>();
}
On Visual Studio this code compiles just fine but on G++ or Clang++, it fails to compile. Errors on G++ 8.3.0:
test.cpp: In static member function ‘static void Struct<x>::F()’:
test.cpp:9:19: error: expected primary-expression before ‘)’ token
Struct<y>::F<0>(); // does not compile?
^
test.cpp: In instantiation of ‘static void Struct<x>::F() [with int y = 0; int x = 0]’:
test.cpp:19:18: required from here
test.cpp:9:15: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘int’ to binary ‘operator<’
Struct<y>::F<0>(); // does not compile?
Errors on Clang++:
5691311/source.cpp:9:19: error: expected expression
Struct<y>::F<0>(); // does not compile?
^
See it live: https://rextester.com/AAL19278
You can change the compiler and copy the code to see the different errors.
Is there anyway I could get around this problem so that my code will compile on G++ or Clang++?
Original Code:
template<int x, int y>
ThisType add()
{
return ThisType::Create(this->x() + x, this->y() + y);
}
ResultPos to = p.add<0, 1>();
template<int x>
struct Struct
{
template<int y>
static void F()
{
Struct<y>::F<0>(); // does not compile?
}
};
should not compile. You need to specify for the compiler that F in fact requires a template list, since F is a dependent template type. Otherwise the compiler will assume that the next < is a smaller than.
template<int x>
struct Struct
{
template<int y>
static void F()
{
Struct<y>::template F<0>();
}
};
I assume Struct<x>::F<0> works, since the compiler already knows that the current type is Struct<x>, but it cannot know that y is the same as xin this case.

GCC template argument deduction/substitution failed

The code below compiles on MSVC but fails on GCC (4.6.3). Why does it fail and what should I do to fix it?
#include <array>
class Foo {
public:
template<typename T, int N>
operator std::array<T, N>() const {
return std::array<T, N>();
}
};
int main(){
Foo val;
// both of the following lines fail on GCC with error:
// "no matching function call...", ultimately with a note:
// "template argument deduction/substitution failed"
auto a = val.operator std::array<int, 2>();
static_cast<std::array<int, 2>>(val);
return 0;
}
EDIT: The following code, however, does compile (on both compilers), despite passing in an int for std::array's template parameter.
template<int N, typename T>
struct Bar {
std::array<T, N> buf;
};
int main()
{
auto x = Bar<3, double>();
return 0;
}
If you read the full text of the error messages you get, the compiler is complaining because the type for N in your template class is int, while the second parameter of std::array is std::size_t, which is an unsigned long on your system.
Changing your template's declaration to use std::size_t N will fix the problem.
MSVC is not complaining possibly because it recognizes that the value "2" works for either case, or because of a compiler bug.

How does this one template compile while this other one gives a syntax error?

I have this template that compiles successfully with g++. When I remove a seemingly irrelevant function, it results in a syntax error.
Exhibit 1: This compiles successfully. Note that this is the only content of the file; the template is not instantiated.
template<typename T> struct aaa {
void w() {
T x;
x.goo<5>();
}
template<float***, char> void goo() {
}
};
Exhibit 2: The following results in a syntax error.
template<typename T> struct aaa {
void w() {
T x;
x.goo<5>();
}
};
The error is
aoeu.cpp: In member function 'void aaa<T>::w()':
aoeu.cpp:6:18: error: expected primary-expression before ')' token
x.goo<5>();
I tried this using GCC 4.8 and 5.2 with the same result. How does the presence of void goo influence whether the line x.goo<5>(); generates an error?

Code compiling on gcc, but not on msvc

I have a problem compiling a template using msvc-2010. It works perfectly using gcc 4.6.3.
I have boiled down the code to the essential (it doesn't make sense of course):
//Variant that works
template <typename T, T* Ptr>
void callFun()
{
}
//Traits class (type expands to the same type T* as above)
template <typename T>
class TraitsClass
{
public:
typedef T* type;
};
//Essentially the same as callFun2, only that the
//type of Ptr is expressed indirectly over a traits class
//The usage of this class is not possible, because of the error described below
template <typename T, typename TraitsClass<T>::type Ptr>
void callFun2()
{
}
//Provides a compile constant ptr for this example
void testFun()
{
}
int main()
{
//Works
callFun<void(), &testFun>();
//Fails
callFun2<void(), &testFun>();
//Works
callFun2<void(), 0>();
return 0;
}
The Error:
error C2975: 'Ptr' : invalid template argument for 'callFun2', expected compile-time constant expression
I find it interesting, that it only fails when the second type parameter is being used through a typedef in a Traits class.
g++ compiles this example correctly without warnings, even when using -Wall -Wextra -Werror -pedantic (Except for the unused parameters, of course)
Thank you very much.
Well, I think that the answer is that compilers are not written by gods. Programming standards in the compiler industry are extremely high, MS C++ is a good compiler, but it still contain bugs. I came across the following, that is somehow similar to what you are pointing at:
template <class item_struct>
struct THeapBasedArray
{
void Sort(int (__cdecl *compareFunction)(const item_struct *item1,
const item_struct *item2));
};
struct Item { int x; };
struct ItemPtrsArray : public THeapBasedArray<Item*>
{
static int __cdecl Compare1(const Item **pp1, const Item **pp2);
typedef Item *ItemPtr;
static int __cdecl Compare2(const ItemPtr *pp1, const ItemPtr *pp2);
};
int main()
{
ItemPtrsArray vect;
vect.Sort(ItemPtrsArray::Compare1);
vect.Sort(ItemPtrsArray::Compare2);
}
The first call to Sort fails with:
cpptest1.cxx(21) : error C2664: 'THeapBasedArray::Sort' : cannot convert parameter 1 from 'int (_cdecl *)(const Item **, const Item **)' to 'int (_cdecl *)(const item_struct *, const item_struct *)
while the second call compilers fine. For me this is a bug in a compiler. Sometimes this happens. I guess this is the answer.