Collision of nested typenames in MSVC - c++

I have encountered a problem while was using variadic templates, but the problem is not related to variadic templates and can be reproduced without them.
The problem is related to same names of types in inherited and base classes.
I've simplified code to the following snippet:
#include <typeinfo>
#include <iostream>
struct A
{
int member;
};
struct B: public A
{
typedef A NEXT;
short member;
};
struct Foo: public B
{
typedef B NEXT;
void Check()
{
std::cout << typeid(NEXT::member).name() << '\n';
std::cout << typeid(NEXT::NEXT::member).name() << '\n';
NEXT::NEXT::member = 1;
NEXT::member = 2;
std::cout << NEXT::NEXT::member << '\n';
std::cout << NEXT::member << '\n';
};
};
int main()
{
Foo foo;
foo.Check();
}
It compiles without warnings and works with GCC and clang, but it produces wrong output with MSVC (at least with Visual Studio 2015 Update 1).
It seems that some collision in names happens, and it treats NEXT::NEXT::member as NEXT::member, but in the same place, it lies to typeid (as well as to std::is_same).
When compiled with GCC or clang the output is:
s
i
1
2
But in case of MSVC, the output is:
short
int
2
2
The following code compiles without warnings with GCC or clang, but as expected produces error with MSVC:
struct A
{
int member;
};
struct B: public A
{
typedef A NEXT;
short member;
};
struct Foo: public B
{
typedef B NEXT;
short& GetB() { return NEXT::member; };
int& GetA() { return NEXT::NEXT::member; };
};
The MSVC error:
source_file.cpp(18): error C2440: 'return': cannot convert from 'short' to 'int &'
Is the code above valid? Is it a problem of MSVC or I'm utilizing UB somehow?
Update
The problem can not be reproduced in MSVC 2015 update 3.

Related

Access type through another type in the same namespace

I have two structs A and B that live in the same namespace. For architectural and compatibility reasons I want to have A accessible through B.
I tried the following which is not working:
#include <iostream>
struct A
{
static void print()
{
std::cout << "hello SO!" << std::endl;
}
};
struct B
{
typedef A A; // error here
};
int main()
{
B::A::print();
return 0;
}
Apparently the typedef to the same name is not working. With g++ I get the following error:
foo.cpp:13:15: error: declaration of ‘typedef struct A B::A’ [-fpermissive]
typedef A A;
^
foo.cpp:3:8: error: changes meaning of ‘A’ from ‘struct A’ [-fpermissive]
struct A
It would work if I give it an other name (e.g. typedef A A2) but I want it to keep the same name.
Interestingly, it is actually working when I compile with clang but I would need code that also builds with gcc.
Is there some way to achieve this (i.e. being able to do B::A::print())?
I am currently using C++11 but going to a newer version might be possible if it is necessary.
just use typedef ::A A or using A = ::A
https://godbolt.org/z/VVKk3V
Here is a solution:
#include <iostream>
namespace NS {
struct A {
static void print() { std::cout << "hello SO!" << std::endl; }
};
struct B {
using A = NS::A;
};
} // namespace NS
int main() {
NS::B::A::print();
return 0;
}
Compiles fine.

Why does the error for converting to pure virtual base class not appear at compilation phase?

I have a contrived example. I think the key point is that there is an illegal conversion into a base class. I should not be able to have an array of MyBase.
This example compiles on my computer in VS2013:
#include <vector>
#include <iostream>
struct MyBase {
virtual size_t Count() = 0;
};
struct MyContainer : MyBase {
size_t Count() override;
};
size_t MyContainer::Count() {
return 4;
}
int main() {
MyContainer countable;
MyBase x[] = { countable };
std::cout << x[0].Count() << std::endl;
return 0;
}
Is this getting the same error on other compilers?
Why am I getting a linker error instead of a compiler warning?
(I do get an Intellisense warning)
Note
The question is not what is happening here or how to fix it. I know that. I was wondering why it is a linker error instead of a compiler error and whether that is specific to my compiler only.
To make it clear, I know that this is a "fix":
int main() {
MyContainer countable;
MyBase * x[] = { &countable };
std::cout << x[0]->Count() << std::endl;
return 0;
}
But fixing is not the issue here. What I do not understand is why the error is not diagnosed by the compiler but instead by the linker.

Ambiguity in a fully qualified static member variable

In this sample code, there is two sentences showing the same static variable. The first one gives no ambiguity, but the second one does, why?
#include <iostream>
using namespace std;
struct A { static const char a = 'a'; };
struct B : public A { };
struct C : public A { };
struct G : public B, public C { };
int main()
{
G v;
cout << G::B::A::a << endl;
cout << v.B::A::a << endl;
}
GCC error (according to some comments, there's no ambiguity in clang):
main.cpp:15:18: error: 'A' is an ambiguous base of 'G'
cout << v.B::A::a << endl;
Code on coliru
This is clearly a bug in GCC, as a GCC maintainer recommends you report it. However, until it's fixed, you can use a nasty workaround like this:
std::cout << static_cast<B &>(v).A::a;
The advantage is this will help disambiguate if in a (complex) scenario that there are variables with the same name in one of the base classes.

VC++ 2013 errors while using member initializer list with lambda as a member

I am having a hard time understanding the origin of these compilation errors.
Following code compiles without any problems on gcc-4.9.3 and clang-3.8 but is failing on VS 2013.
class Sample
{
public:
template<typename T>
explicit Sample(T& in) :
x(in),
lamb( [](Sample& ss)
{
std::cout << "This works !!\n" << static_cast<const T&> (ss.get()) << std::endl;
}){}
const int get() const { return x; }
private:
int x;
std::function<void(Sample&)> lamb;
};
int main()
{
int z = 10;
Sample a(z);
return 0;
}
I end up with following errors:
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
error C2061: syntax error : identifier 'T'
The MSDN explaination for these errors did not help much. What am I doing wrong here?
It looks that visual studio doesn't pass info about template type T into lambda. I've passed class variable to lambda to gather needed type info. Something like this works:
#include <functional>
#include <iostream>
class Sample
{
public:
template<typename T>
explicit Sample(T& in) :
x(in),
lamb( [this](Sample& ss)
{
std::cout << "This works !!\n" << static_cast<decltype(x)> (ss.get()) << std::endl;
}){}
const int get() const { return x; }
private:
int x;
std::function<void(Sample&)> lamb;
};
int main()
{
int z = 10;
Sample a(z);
return 0;
}

Is this name lookup in dependent base class with VC++ 2010 non-standard?

The code below does not compile on Ideone or Codepad, yielding errors like:
'X' was not declared in this scope
but it does on VC++ 2010:
#include <iostream>
#include <typeinfo>
template<typename T>
struct Base
{
typedef T X;
};
template<typename T>
struct Derived
:
Base<T>
{
static void print()
{
std::cout << typeid(X).name() << "\n";
}
};
int main()
{
Derived<int>::print();
Derived<char>::print();
Derived<float>::print();
return 0;
}
where it prints int, char and float. Should I change my code to:
template<typename T>
struct Derived
{
typedef Base<T> B;
static void print()
{
std::cout << typeid(typename B::X).name() << "\n";
}
};
in order to be standard-conforming?
If you meant the equivalent of this (note you have dropped the inheritance in your example):
template<typename T>
struct Derived : Base<T> {
static void print() {
std::cout << typeid(typename Base<T>::X).name() << "\n";
}
};
then yes, that is standard compliant code. But note that the result of typeid(some type).name() is implementation dependent. On GCC your main produces i, c and f.
$ g++ -Wall test.cpp
test.cpp: In static member function 'static void Derived::print()':
test.cpp:15:37: error: 'X' was not declared in this scope
$ g++ --version
g++ (SUSE Linux) 4.6.2