When we compile codes in VC, we somethings have the C4251 warnings. In my case, most of the warnings come from the fact that STL is a member of the _declspec(dllexport) class. In order to have a deep understanding of the warning, I plan to create a class that will intrigue the warning. I have tried the following cases, but no C4251 warning is given, and I was wondering whether a simple example can be given. Thanks!
The cases I have tried:
class _declspec(dllexport) ClassTest
{
public:
ExportClass<int> myexport;
ClassUse myuse;
int i;
};
Case 1:
template <typename T>
class ExportClass
{
public:
T a;
T b;
};
Case 2:
class ClassUse
{
public:
int counts;
float f_value;
std::vector<int> abc;
void get_func();
template <typename T>
T ouput_value()
{
return static_cast<T>(3);
};
template<class T>
int connected()
{
T abc;
return 3;
}
};
EDIT:
I want to make it clear that the warning will not comes from invoking STL.
You should consider MSDN in that particular case:
Compiler Warning (level 1) C4251
'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
this can happen when
// C4251.cpp
// compile with: /EHsc /MTd /W2 /c
#include <vector>
using namespace std;
class Node;
class __declspec(dllimport) VecWrapper : vector<Node *> {}; // C4251
This page gives an example of a class that gives the warning message.
See following example if you want to generate the warning message without making use of STL:
class __declspec(dllimport) Foo
{
public:
Foo();
CString m_str; // WARNING C4251 HERE
};
Related
I have a templated class:
template <typename vtype>
class BNode
{
public:
BNode::BNode(std::vector<BPoly<vtype>>& thePolys) {if(thePolys.size()) Build(thePolys);}
BNode::BNode() {}
BPlane* mPlane=nullptr;
//And more stuff
};
When I compile, I get this error on the BPlane* mPlane=nullptr line:
error C2146: syntax error: missing ';' before identifier 'BPlane'
(Using Visual Studio 2019 compiler)
Why do I need a semicolon after my {}? If I put the semicolon there, it works. But I'm curious what the problem is because I'm worried there's some issue that will bite me later.
The following code compile without any error:
#include <vector>
class BPlane;
template <class T> class BPoly { int i; };
template <typename vtype>
class BNode
{
public:
BNode(std::vector<BPoly<vtype>> &thePolys) { if (thePolys.size()) Build(thePolys); }
BNode() {}
BPlane *mPlane = nullptr;
void Build(...) {}
//And more stuff
};
int main()
{
BNode<char> s;
}
Thus, it is impossible to guess what you have done wrong as after writing simple types for missing declaration and including vector the code compile without adding any ; after a constructor.
And I have made an instantiation in main to be sure that the class is used.
I have a header file (say the_foo.h) which defines/declares the following classes:
// \file the_foo.h
class FooBase
{
virtual size_t bar_size() = 0;
};
template<class Bar>
class Foo : public FooBase
{
size_t bar_size() { return sizeof(Bar); }
};
class TheBar; // TheBar forward declaration
class TheFoo : public Foo<TheBar>
{
};
Compiling with MS vc14 (Visual Studio 2015), I notice the following behaviors:
Any cpp file which includes the_foo.h and defines TheBar, eg:
#include "the_foo.h"
class TheBar {}; // TheBar definition
will compile just fine. However,
Any cpp file which includes the_foo.h and DOES NOT DEFINE TheBar, eg:
#include "the_foo.h"
fails to compile with error: the_foo.h(11): error C2027: use of undefined type 'TheBar'
The cpp file compiled above contains one single line: inclusion of the header, no more code.
Removing the virtual member function declaration virtual size_t bar_size() = 0; does fix the error.
Thanks to answer from Sam Varshavchik, this code compile fine using gcc 5.3.1, so this issue is clearly compiler specific.
My questions are:
Why does compilation fail in case (2), when TheBar is forward declared only ?
Is there any way to make case (2) compiling successfully under vc14, i.e. without an explicit definition of TheBar, which class I need to keep opaque in some cpp files ?
PS: I edited the code sample of this question in order to make clear what actually causes the issue described in the question. The original code sample (which is quoted in the answer from Sam Varshavchik) may indeed have misleaded on the actual cause of the issue and, consequently, leaded to answers and comments out of the question scope.
Your test case compiles without issues with gcc 5.3.1:
$ cat t.C
class FooBase
{
public:
FooBase() {}
virtual ~FooBase() {}
};
template<class Bar>
class Foo : public FooBase
{
public:
Foo() { sizeof(Bar); bar = new Bar; }
~Foo() { sizeof(Bar); delete bar; }
Bar* bar;
};
class TheBar;
class TheFoo : public Foo<TheBar>
{
public:
TheFoo();
~TheFoo();
};
[mrsam#octopus tmp]$ g++ -c -o t.o t.C
[mrsam#octopus tmp]$
The answer here appears to be "you're using an old C++ compiler that does not correctly compile this".
The compiler searches for a definition of the class TheBar when you try to construct or delete it in the constructor and destructor of the Foo class. It means it needs the implementation at that point, otherwise it has no idea what to do.
If make the following example:
The first header:
// foobase.h
class FooBase
{
public:
FooBase() {}
virtual ~FooBase() {}
};
template<class Bar>
class Foo : public FooBase
{
public:
Foo() { bar = new Bar; }
~Foo() { delete bar; }
private:
Bar* bar;
};
class TheBar;
class TheFoo : public Foo<TheBar>
{
public:
TheFoo() {};
~TheFoo() {};
};
The next header
// thebar.h
class TheBar {};
And the following main file:
// foo_main.cxx
// #include "thebar.h" // Including this include makes the program run
#include "foobase.h"
int main()
{
TheFoo thefoo;
return 0;
}
Then your compiler will tell you what is wrong (only first error shown):
./foobase.h:14:32: error: allocation of incomplete type 'TheBar'
Foo() { bar = new Bar; }
Including thebar.h will solve the problem.
I'm writing for a project that uses makefile rules to switch between GPU and CPU implementations. I'd like to present an interface to user code that automatically switches between implementations without having to write #ifdef GPU_MODE all over the place.
My solution had been to use a templated interface class followed by alias templates (just typedefs, really, but I like the left-to-right style) like so:
namespace INTERFACE{
template <class VERSION>
class MyClass{
public:
MyClass():theClass(){};
//more methods...
private:
VERSION theClass;
};
}
using CpuMyClass = INTERFACE::MyClass<CpuMode>; //CpuMode defined elsewhere
#ifdef GPU_MODE
using MyClass = INTERFACE::MyClass<GpuMode>;
#else
using MyClass = INTERFACE::MyClass<CpuMode>;
#endif
Thus allowing outside code to use the symbol MyClass freely, trusting it to switch between modes automatically. Unfortunately using this is proving confusing. For example, I have a second class for which I'd like to write a ctor from MyClass:
#include "MyClass.hpp"
class OutsideClass{
public:
OutsideClass(const MyClass& A);
};
This ctor triggers an "identifier 'MyClass' is undefined" error. Does anyone know what's going on here?
Did you mean something like:
struct GpuMode { };
struct CpuMode { };
namespace INTERFACE {
// ~~~~~~~~^^^^^^
template <class VERSION>
class MyClass{
public:
MyClass() : theClass(){};
//more methods..
private:
VERSION theClass;
};
}
using CpuMyClass = INTERFACE::MyClass<CpuMode>; //CpuMode defined elsewhere
#ifdef GPU_MODE
using MyClass = INTERFACE::MyClass<GpuMode>;
#else
using MyClass = INTERFACE::MyClass<CpuMode>;
#endif
class OutsideClass{
public:
OutsideClass(const MyClass& A);
};
Demo
I have a problem with class member function templates. It seems that gcc is trying to analyze the code semantically too early, without explicit template instantiation.
Let the code speak
A.h (the base class):
#ifndef __A_H__
#define __A_H__
class A {
public:
A* ptr;
template<class T>
void method() {
((B*) ptr)->invoke();
}
};
#endif
B.h (the ancestor):
#ifndef __B_H__
#define __B_H__
#include<cstdio>
class B : public A {
public:
void invoke() {
printf("Method invoked\n");
}
};
#endif
main.cpp:
#include"A.h"
#include"B.h"
int main() {
A a;
a.ptr = new B();
a.method<int>();
}
This code compiles and runs fine in Visual Studio 2010 and fails to compile with following error on gcc 4.5:
In file included from main.cpp:1:0: A.h: In member function ‘void
A::method()’: A.h:10:5: error: ‘B’ was not declared in this scope
A.h:10:7: error: expected primary-expression before ‘)’ token
A.h:10:9: error: expected ‘)’ before ‘ptr’
Why is gcc trying to compile code of A::method<>() before any instantiation is requested? Which compiler behaves according to the standard?
UPDATE: Now I know that Visual Studio behaves incorrectly. B is not template parameter dependant, so it's not looked up at instantiation, but during parsing of A.h. (relevant gcc doc)
The code incorrectly compiles in Visual Studio due to the way templates are processed (basically they are ignored until they get instantiated). In your code, the identifier B is not dependent on the template arguments (T) and as such, it must be available in the context where the template is defined.
As B inherits from A, that makes everything even more complicated, as you have a cyclic dependency in the code. I would reconsider the design, and if you consider that it needs to be so, I would merge the two header files into a single one:
// merged.h
struct A {
A* ptr;
template<class T>
void method();
};
struct B : public A {
void invoke() {
printf("Method invoked\n");
}
};
template <typename T>
void A::method() {
((B*) ptr)->invoke();
}
Still, my advice would be to reconsider whether that relantionship makes sense at all, as method imposes the restriction that ptr must be a B, and that rings some bells of code smell.
ne555 from cplusplus.com forum gave me some neat solution:
new A.h:
#ifndef __A_H__
#define __A_H__
class A {
public:
A* ptr;
template<class T>
void method();
};
#include"B.h"
template<class T>
void A::method(){
((B*)ptr)->invoke();
}
#endif
i got a compile error which i do not understand.
i have a h/cpp file combination that does not contain a class but just defines some utility functions. when i try to use a struct that is defined in another class i get the error:
error C2027: use of undefined type 'B::C'
so, stripped down to the problem, the h-file looks like this
namespace A {
void foo(B::C::SStruct const & Var);
}
the definition of SStruct is in a class which is in another h-file, that is of course included.
namespace B {
class C {
public:
struct SStruct { };
};
}
the strange thing is, i can use this struct in other classes fine, it just seems to be related to this one h-file which contains just utility functions.
what am i missing here?
thanks!
After correcting missing semicolons etc. this compiles:
namespace B {
class C {
public:
struct SStruct { };
};
}
namespace A {
void foo(B::C::SStruct const & Var);
}
Obviously, if the order of the two namespaces were switched, this would not work. Possibly you are #including your headers in the wrong order. If this is the error, that's bad design - you should not allow header order to matter in your code.
I assume you meant "class C", not "Class C".
struct SStruct is private to class C (private being the default visibility of class members).
As such, it is not visible outside class C and its friends, which does not include A::foo().
Class C {
struct SStruct { };
}
==>
class C {
public:
struct SStruct { };
};
Your class is missing a semicolon after the definition. It should be:
namespace B {
class C {
public:
struct SStruct { };
}; // <=== Here
}