I have some C++ code I'm trying to compile in Visual Studio 2013, but I'm running into an error. Here's a simplified testcase that demonstrates the problem:
template <typename SomeEnum>
struct Inner {
SomeEnum variant;
int innerVal;
};
template <typename SomeEnum>
struct Outer {
int outerVal;
union {
Inner<SomeEnum> inners[10];
unsigned char data[20];
};
};
enum MyEnum {
VAR1,
VAR2
};
int main() {
Outer<MyEnum> outer;
return 0;
}
This gives me the error main.cpp(11): error C2621: 'Outer<MyEnum>::inners' : illegal union member; type 'Inner<SomeEnum>' has a copy constructor. It seems like Inner<SomeEnum> should be as POD as they come. Is this a known problem, or is the code invalid for a reason of which I'm not aware? Some Googling yielded no results on the issue.
The example compiles if I either Inner not a template class or if inners is not an array, but unfortunately neither of those is an option for my actual code. Are there any other ways I could accomplish the same thing?
It works on ideone.com, leading me to think it may be a VS2013 bug. You could try VS2015 if you can.
A possible workaround is to explicitly specialize for each enum you want to use.
Adding this after the MyEnum definition:
template <>
struct Inner<MyEnum> {
MyEnum variant;
int innerVal;
}
Makes the error go away for some reason. Obviously that will lead to a ton of duplicated code, which is what templates are trying to stop. You could possibly write a macro (ugh) to make this template specialization for you.
Related
I have a project with quite a lot of function templates that I wrote back in Visual Studio 2017, and it always worked fine. Now I have to build it in VS2019, because I need to include the lib in another project that is written in VS2019, and the thing won't build.
There is one function template it seems to take issue with, although it doesn't actually complain about the function itself. The compiler just says "identifier not found" when I invoke it in the code. The thing is there in the namespace, however, even InteliSense sees it and links to it without complaining. Just the compiler won't.
Here's the code in question:
// declaration
namespace Oparse
{
// lots of other functions, many of them templates
template <typename T> OpModel<T> *_ModelPtr(T *receiver) { return new OpModel<T>(receiver); };
}
// Invocation
namespace Oparse
{
template <class T, class U>
class OpModelFactory
: public OpNestable
{
public:
OpModelFactory<T, U>(vector<U*> &receiver) : OpNestable(OP_MODELFACTORY), receiver(receiver) {};
// other stuff
void Serialize(string key, stringstream &stream, unsigned int indents)
{
for (unsigned int i = 0; i < receiver.size(); ++i)
{
// check if the instances are really of the type of this OpModel, otherwise there may be duplicates between polymorphic factories populating the same receiver.
T *currentModel = dynamic_cast<T*>(receiver[i]);
if (currentModel != NULL)
{
OpModel<T> *parser = _ModelPtr<T>(currentModel); // <-- identifier not found
parser->Serialize(key, stream, indents);
delete parser;
}
}
};
private:
vector<U*> &receiver;
}
}
If I comment that invocation, the project builds, despite there being a whole lot more function templates declared right where this one is. I have no clue what to do to make the linker find it. Are there any Visual Studio wizzards who could give me a hint? I must honestly confess that I haven't used the IDE in years, and it's my first time in Visual Studio 2019...
Here's the complete output of the error. There's a second message to it, but I found it perfectly unhelpful:
1>D:\Orbiter_installs\Orbiter2016\Orbitersdk\Oparse\include\OpModel.h(138,27): error C3861: '_ModelPtr': identifier not found
1>D:\Orbiter_installs\Orbiter2016\Orbitersdk\Oparse\include\OpModel.h(152): message : see reference to class template instantiation 'Oparse::OpModelFactory<T,U>' being compiled
And no, there's not further message attached. I have seen similar messages that usually go on with "with ... $further information", but this is all I get.
There is a circular dependency problem.
In Oparse.h, you first include OpModel.h that requires_ModelPtr in implementation of Serialize , but_ModelPtr is only defined later in the header.
You need to forward declare the template method.
In OpModel.h, write this instead:
namespace Oparse
{
template<typename T> class OpModel;
template <typename T> OpModel<T>* _ModelPtr(T* receiver);
// Remaining of OpModel.h...
typedef map<string, pair<Oparse::OpValue*, vector<Oparse::OpValidator*>>> OpModelDef;
typedef vector<pair<Oparse::OpValue*, vector<Oparse::OpValidator*>>> OpValues;
...
I have an odd issue in MSVS 2010. I have a class with a function that is templitized and contains an parameter with a default value.
In my header file:
typedef unsinged int data32
class myClass
{
private:
...
public:
...
template <typename T>
T* myF(data32);
}
...
template<typename T>
T* myClass::myF(data32 size = 1)
{
...
}
Ok, now in my main i have something like this:
int main()
{
myClass A;
data32* myInt = A.myF<data32>(100); // no complaints from pre-compiler
data32* myInt2 = A.myF<data32>(); // pre-compiler complains "Error: no instance of the function template "myClass::myF" matches the argument list"
}
I understand why it is unhappy as i do not have a function prototype defined for 'myF()' in the class, but shouldn't it know better? I thought the point of defaults were to make the parameters optional in the call. The code DOES compile and run just fine even thought the pre-compiler is unhappy and flags this as a problem.
Any thoughts??
Thanks!
There are bugs (false alarms) in the intellisense analyzer in VS 2010. And this seems like one of them. The analyzer used for intellisense is different from the actual parser used in compiler.
template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};
#define STATIC_CHECK(expr,msg) {CompileTimeError< ((expr)!=0) > Error_##msg; (void)Error_##msg; }
template <class To , class From>
To safe_reinterpret_cast(From from)
{
STATIC_CHECK(sizeof(From) <= sizeof(To),Destination_Type_Too_Narrow);
return reinterpret_cast<To>(from);
}
void main()
{
void *p= NULL;
char c= safe_reinterpret_cast<char>(p);
}
Above code works fine and gives compile time error when we try to convert pointer to char .
But its not very clear how STATIC_CHECK macro works.
As per above code it should lead to following
STATC_CHECK(false,Destination_Type_Too_Narrow)
Above macro will get expanded as follows:
CompileTimeError<false>
ERROR_Destination_Type_Too_Narrow;
(void)ERROR_Destination_Type_Too_Narrow;
In above macro I am not able to understand what these two statements are meant for
ERROR_Destination_Type_Too_Narrow;
(void)ERROR_Destination_Type_Too_Narrow;
If anyone having clear understanding please explain
We have specialization for class CompileTimeError<true>, that has default constructor. Instanciations of other cases will cause error, that CompileTimeError<not true> is undefined type (in your case we trying to create variable ERROR_Destination_Type_Too_Narrow of type CompileTimeError<false>). (void)VariableName is only silence of -Wunused
Embarrassingly simple problem here. I am trying to use std::array and am tripping at the first hurdle with the error ...
implicit instantiation of undefined template 'std::__1::array<char,10>'
The code that gives the error is shown below. I can work around it with std::map for now, but I'm sure the fix must be simple!!
enum p_t {
EMPTY = 0
,BORDER_L
// ...
,BORDER_BR
,DATUM
,NUMEL };
class PlotChars
{
array<char, p_t::NUMEL> charContainer;
// error on this ^ line:
// implicit instantiation of undefined template 'std::__1::array<char,10>'
};
My first guess would be that you simply forgot to:
#include <array>
...before trying to use the array template. While you can (at least indirectly) use a few classes without including the headers (e.g., the compiler can create an std::initializer_list from something like {1, 2, 3} without your including any headers) in most cases (including std::array) you need to include the header before using the class template.
You are using a C-style enum, so you probably need to omit the enum name, if your compiler isn't fully C++11 compliant.
array<char, NUMEL> charContainer;
This works on gcc 4.4.3, whereas the equivalent to your code does not yet work on that version (but does on later ones)
#include <array>
enum XX { X,Y,Z };
struct Foo
{
std::array<char, Y> a;
};
int main()
{
Foo f;
}
Try with that
std::array<char, (int)NUMEL> charContainer;
I'm using Visual Studio 2008 with the Boost v1.42.0 library. If I use an enum as the template argument, I get a compile error when adding a value using push_back(). The compiler error is: 'T': is not a legal base class and the location of the error is move.hpp line 79.
#include <boost/interprocess/containers/vector.hpp>
class Test {
public:
enum Types {
Unknown = 0,
First = 1,
Second = 2,
Third = 3
};
typedef boost::container::vector<Types> TypesVector;
};
int main() {
Test::TypesVector o;
o.push_back(Test::First);
return 0;
}
If I use a std::vector instead it works. And if I resize the Boost version first and then set the values using the [] operator it also works.
Is there some way to make this work using push_back()?
Template backtrace of the error:
error C2516: 'T' : is not a legal base class
1> main.cpp(21) : see declaration of 'T'
1> main.cpp(21) : see reference to class template instantiation 'boost::interprocess::rv' being compiled
1> with
1> [
1> T=Test::Types
1> ]
I think you have find really a bug. I have posted to the Boost ML to track the issue and try to have more info.
For the moment the single workaround I see is to specialize the rv class as follows, but I'm not sure this will work on all the cases.
namespace boost {
namespace interprocess {
template <>
class rv<Test::Types>
{
Test::Types v;
rv();
~rv();
rv(rv const&);
void operator=(rv const&);
operator Test::Types() const {return v;}
};
}}
If this do not works you can try using int instead of enum.
enum {
Unknown = 0,
First = 1,
Second = 2,
Third = 3
};
typedef int Types;
Of course this has the drawback to loss the enum safety.
It sounds like Boost has some erroneous logic to determine whether to derive from T or not.
Naively, one might assume that any type besides a native type or pointer may be used as a base. However enums are neither bases nor primitive. Perhaps they failed to account for that.
It looks like Boost is incorrectly determining that enums are compatible with its rvalue-reference emulation.
The best way to solve this is to avoid use of enums in Boost Interprocess structures.
A hack like
namespace boost {
namespace interprocess { // get inside boost
template<>
class is_movable<Test::Types> // add custom specialization of is_movable
: public ::boost::mpl::bool_<false>
{};
}}
might patch things up. Untested.
Add this right after your #includes so it appears before the first use.