I have some template class that has two private static members.
Users define a traits struct and provide it to the template class, which then derives from it.
Then in a c++ file the user define the static members, with one member initialized from the other.
For some reason I get a "class has not been declared" error if I dont fully specify the namespace for the arg. This is only an issue when I'm in a nested namespace, there is no issue if you define the type in a single top level namespace, which makes me think this is a compiler bug.
Trimmed down example below, compiling with gcc 7.2
template<typename Traits>
struct Base
{
static int x;
static int y;
};
namespace foo::bar
{
struct BarTraits
{
};
using Bar = Base<BarTraits>;
template<> int Bar::x = 0;
template<> int Bar::y( Bar::x ); //error
//template<> int Bar::y( foo::bar::Bar::x ); //no error
}
According to C++ standard temp.expl.spec#3
An explicit specialization may be declared in any scope in which the corresponding primary template may be defined.
Your code violates this statement, because Bar::x and Bar::y are specialized in namespace foo::bar.
GCC incorrectly accepts first two specializations because of known defect https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56119
The following fixed code
template<typename Traits>
struct Base {
static int x;
static int y;
};
struct BarTraits {};
using Bar = Base<BarTraits>;
template<> int Bar::x = 0;
template<> int Bar::y( Bar::x );
is accepted by GCC, Clang, MSVC: https://gcc.godbolt.org/z/MPxjTzbah
Related
I have a templete class and in which i have defined a static object of another class but when I run the code in windows it builds without an error but exactly the same code gives me this error when I build this on linux machine.
source.cpp:24:13: error: specializing member ‘classB<int>::Buffer’ requires ‘template<>’ syntax
using namespace std;
template<class T>
struct classA {
T a;
public:
classA(int size)
{
a = size;
}
};
template<class T>
struct classB {
classA<int> static Buffer;
T a;
};
classA<int> classB<int>::Buffer(120);
int main()
{
classB<int> Recorder;
return 0;
}
classA<int> classB<int>::Buffer(120)
must be changed to
template<class T> classA<int> classB<T>::Buffer(120)
The classA can take any type, not only int. You have defined it only for int, The other compiler (Linux) could find there an error.
I'm working on a project with a pre-made .hpp file with all the declarations and stuff.
A struct is declared in the private part of the class, along with some private members.
I need to create an array with the type of the struct in my .cpp file.
//.hpp
private:
struct foo
{
std::string a;
unsigned int b;
};
std::string* x;
unsigned int y;
//.cpp
unsigned int returny()
{
return y; // No errors
}
foo newArray[10]; // Compile time error; unknown type name
Why is it that I can return y, which is also private, but not make an array out of the struct foo?
How can I fix this? (I'm in an introductory C++ class... so hopefully there's a simple solution)
There are couple of issues.
You can't use a type that's defined in the private section of class like you are trying.
The nested type can be used by specifying the appropriate scope.
EnclosingClass::foo newArray[10];
But this will work only if foo is defined in the public section of EnclosingClass.
you should define the struct int the outside of the class like this
struct Foo
{
std::string a;
unsigned int b;
};
class A {
private:
Foo foo;
...
}
The following code compiles using GCC 4.4.6 and Comeau 4.3.10.
#include <iostream>
struct A { int name; };
template<typename T> struct C : T { using T::name; };
struct B : private A { friend struct C<B>; };
int main()
{
C<B> o;
o.name = 0;
}
It gives the following error in VC++10:
main.cpp(4): error C2877: 'A::name' is not accessible from 'A'
main.cpp(10): error C2247: 'A::name' not accessible because 'B' uses 'private' to inherit from 'A'
What's a good cross-compiler workaround that allows o.name = 0;?
Note: Adding using A::name to B takes care of the problem, but publishes the A::name member to everyone, whereas it should only be visible to a particular template instantiation, namely C<B>.
Work around is what #kerrekSB suggested, add using A::name; in class B:
struct A { int name; };
template<typename T> struct C : T { using T::name; };
struct B : private A {
using A::name;
friend struct C<B>;
};
your initial example didn't work cause class A is private to B and class C<B> is friend of B but when you access member name from object of C<B> , line using T::name; creates problem since the class B doesn't has any member name in it. it's scope search which find the member name when you try to access it via object of class B
Edit :
Adding using A::name to B takes care of the problem, but publishes the
A::name member to everyone, whereas it should only be visible to a
particular template instantiation, namely C
if that's the case , then simply declare statement using A::name; in private section in class B i.e
struct B : private A {
protected: using A::name;
public:
friend struct C<B>;
};
There seems to be a fundamental difference in visibility considerations between gcc and VC++ when using member using-declarations; check this simplified example without templates:
struct A { int name; };
struct B: private A { friend struct C; };
struct C: B {using B::name; };
int main()
{
C o;
o.name = 0;
}
It will compile on gcc but not on VC++ (with basically the same error as in the question). Will have to consult the standard on who is doing it right...
I can't seem to init an static member inside an fully specialized class template!
I'm trying to do the following:
template<typename Type>
class X
{
};
template<>
class X<int>
{
public:
static int Value;
}
But i can't seem to init the static member, i tried everything like:
template<>
int X<int>::Value = 0;
It doesn't compile, so any pointers on how to actually do this would be nice ;)
Edit: the answer beneath is correct but you also need to place the init in the .cpp file and not in the header file.
Thanks for your time,
Richard.
Don't use template<> while defining Value because template<> is not allowed in member definition of explicitly specialized class[X<int> in this case]. Moreover you are missing a semicolon after }
This works for me:
template<typename Type>
class X
{
};
template<>
class X<int>
{
public:
static int Value;
};
int X<int>::Value = 0;
I have seen following style class definition several times. What exactly are the pros/cons of this style?
typedef class _MyClass
{
public :
_MyClass();
} MyClass;
It's pretty rare in C++, but common in C (where struct Foo does not automatically alias to just Foo.) You might see it in a library that has different classes for different platforms (e.g. a "Canvas" class, which is very implementation-specific.) The library would use the typedef to let its users simplify their code:
#if WINDOWS
typedef class WindowsCanvas {
private: HWND handle;
} Canvas;
#elif MAC
typedef class MacCanvas {
private: CGContextRef context;
} Canvas;
#endif
In such an example, one would only need to use the Canvas type, never the platform-specific types.
In C++ there are no pros. This style came from C where you couldn't just use the struct's name as a type. E.g.
struct X
{
int x;
};
X a; //compiler error
struct X b; //OK
in order to avoid using the elaborated type specifier, like struct X a, or enum E e; etc. in C it is a common practice to typedef the name.
E.G.
typedef struct X_ { ... } X;
Now X a; is OK too.
Naturally in C++ there is no need to do this.
One possible advantage is illustrated by a highly contrived example, but since the Standard speaks of it, it must be having an impliciation for sure.
$7.1.3/6- "Similarly, in a given
scope, a class or enumeration shall
not be declared with the same name as
a typedef-name that is declared in
that scope and refers to a type other
than the class or enumeration itself.
[
typedef struct S{} MYS;
int MYS; // Error due to $7.1.3/6
struct A{};
int A; // No error, subsequent use required fully elaborated name
int main(){}