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;
...
Related
Here is a small,standalone use case that I am trying to compile using VS2015 Update 3 compiler.
template <typename Derived, typename SomeType> class BaseClass
{
public:
void NameHidingMethod(SomeType const & node)
{
// Do Something
}
};
namespace structured {
typedef struct _Structure
{
} Structure;
template <typename Derived>
using BaseClass = BaseClass<Derived, Structure>;
}
class DerivedClass : public structured::BaseClass<DerivedClass>
{
public:
using structured::BaseClass<DerivedClass>::NameHidingMethod; // Generates error
};
int main() {
return 0;
}
This works fine on VS 2013 but fails VS 2015 Update 3. Here is the error message that I get.
fatal error C1001: An internal error has occurred in the compiler.
(compiler file 'f:\dd\vctools\compiler\cxxfe\sl\p1\c\symbols.c', line 5786)
To work around this problem, try simplifying or changing the program near the locations listed above.
Please choose the Technical Support command on the Visual C++
Help menu, or open the Technical Support help file for more information
Is my code legit ? If yes, then what could be a possible workaround ?
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.
I'm trying to port some code written for MSVC over to compile on Clang. However it seems to be having a problem finding some template functions. Here is part of the definition of the struct that is giving me problems:
template< typename T > struct FixedVector
{
T * ptr;
size_t count;
typedef T value_type;
FixedVector():ptr(0),count(0) {}
~FixedVector()
{
DeleteArr(ptr); // Error message appears here
count=0;
}
// ...
}
The DeleteArr(ptr) function refers to a function defined later on, like so:
template< typename T > inline void DeleteArr( T *& ptr )
{
delete[] ptr;
ptr = NULL;
}
This is the error message I get on the line indicated:
error: call to function 'DeleteArr' that is neither visible in the template definition nor found by argument-dependent lookup
Looking at the full drop-down list for the error (in Xcode), the following message is at the bottom of the list:
'DeleteArr' should be declared prior to the call site or in an associated namespace of one of its arguments.
Clicking on this message brings me to the definition of the DeleteArr() function, as shown above.
This apparently compiled fine in MSVC, and from looking around at the differences between Clang and MSVC, this is due to a quirk in MSVC that doesn't require functions like this to be defined before they're used, as long as there is a definition somewhere. So I looked up this error message in the Clang documentation (relevant part is under the title "Unqualified lookup in templates") and it suggested adding a forward declaration before the template definition. So I added this above the definition for FixedVector:
template< typename T > inline void DeleteArr( T *& ptr );
However, this error message is still coming up, and that final bit of the error message (the 'should be declared prior to the call site' bit) still points to the actual definition of the function. Does anyone know what may be the problem? I'm all out of ideas as to how this is valid on MSVC. Also, since the error message can find the definition of the function, why is it saying it can't be found?
UPDATE: At the advice of the comments, I've added the implementation of DeleteArr() to where I declared it above the template. This seems to result in the same error! I'm really stumped now.
The declaration of DeleteArr must be available to FixedVector, i.e. the definition of the former has to come before the use by the latter. This is likely related to the failure of MSVC to correctly implement the two-phase lookup.
first define DeleteArr
template< typename T > inline void DeleteArr( T *& ptr )
{
delete[] ptr;
ptr = NULL;
}
Then define fixedvector
template< typename T > struct FixedVector
{
T * ptr;
size_t count;
typedef T value_type;
FixedVector():ptr(0),count(0) {}
~FixedVector()
{
DeleteArr(ptr); // Error message appears here
count=0;
}
// ...
}
I think I've run into a (possible) VC6 (I know. It's what we use.) compiler error, but am open to the fact that I've just missed something dumb. Given the following code (It's just an example!):
#include <iostream>
// Class with template member function:
class SomeClass
{
public:
SomeClass() {};
template<class T>
T getItem()
{
return T();
};
};
// Dummy just used to recreate compiler error
class OtherClass
{
public:
OtherClass() {};
};
std::ostream& operator<<( std::ostream& oStr, const OtherClass& obj )
{
return oStr << "OtherClass!";
};
// Main illustrates the error:
int main(int argc, char* argv[])
{
SomeClass a;
OtherClass inst2 = a.getItem<OtherClass>(); // Error C2275 happens here!
std::cout << inst2 << std::endl;
return 0;
}
If I try to compile this code VC6, dies on a.getItem<OtherClass>() yielding:
Error C2275: 'OtherClass' : illegal use of this type as an expression.
Have I overlooked some trivial syntax issue? Am I breaking a rule?
This code compiles just fine under gcc 4.3.4. Is it yet another compliance issue with VC6?
Thanks!
Among many other things with the word template in it, VC6 couldn't deal with function templates where the template parameters aren't also function parameters. The common workaround was to add a dummy function parameter:
template<class T>
T getItem(T* /*dummy*/ = NULL)
{
return T();
} // note: no ; after function definitions
However, in general, VC6 is pretty lame and often chokes as soon as a TU contains the template keyword. I had to beat my head against it for several years (big code base compiled with several compilers/compiler versions; VC6 giving us an endless amount of trouble) and was very glad when I got rid of it in 2003.
This is likely to be a VC6 issue. Although VC6 compiles most basic templates correctly it is known to have many issues when you start to move towards the more advanced template uses. Member templates are an area where VC6 is known to be weak on conformance.
I believe that's another bug in VC6, you should really switch to a more up-to-date compiler.
Been away from C++ for a few years and am getting a linker error from the following code:
Gene.h
#ifndef GENE_H_INCLUDED
#define GENE_H_INCLUDED
template <typename T>
class Gene {
public:
T getValue();
void setValue(T value);
void setRange(T min, T max);
private:
T value;
T minValue;
T maxValue;
};
#endif // GENE_H_INCLUDED
Gene.cpp
#include "Gene.h"
template <typename T>
T Gene<T>::getValue() {
return this->value;
}
template <typename T>
void Gene<T>::setValue(T value) {
if(value >= this->minValue && value <= this->minValue) {
this->value = value;
}
}
template <typename T>
void Gene<T>::setRange(T min, T max) {
this->minValue = min;
this->maxValue = max;
}
Using Code::Blocks and GCC if it matters to anyone. Also, clearly porting some GA stuff to C++ for fun and practice.
The template definition (the cpp file in your code) has to be included prior to instantiating a given template class, so you either have to include function definitions in the header, or #include the cpp file prior to using the class (or do explicit instantiations if you have a limited number of them).
Including the cpp file containing the implementations of the template class functions works. However, IMHO, this is weird and awkward. There must surely be a slicker way of doing this?
If you have only a few different instances to create, and know them beforehand, then you can use "explicit instantiation"
This works something like this:
At the top of gene.cpp add the following lines
template class Gene<int>;
template class Gene<float>;
In if(value >= this->minValue && value <= this->minValue) the second minValue should be maxValue, no?
Echo what Sean said: What's the error message? You've defined and declared the functions, but you've not used them in anything anywhere, nor do I see an error (besides the typo).
TLDR
It seems that you need an Explicit Instantiation i.e. to actually create the class. Since template classes are just "instructions" on how to create a class you actually need to tell the compiler to create the class. Otherwise the linker won't find anything when it goes looking.
The thorough explanation
When compiling your code g++ goes through a number of steps the problem you're seeing occurs in the Linking step. Template classes define how classes "should" be created, they're literally templates. During compile time g++ compiles each cpp file individually so the compiler sees your template on how to create a class but no instructions on what "classes" to create. Therefore ignores it. Later during the linking step the g++ attempts to link the file containing the class (the one that doesn't exist) and fails to find it ultimately returning an error.
To remedy this you actually need to "explicitly instantiate" the class by adding the following lines to Gene.cpp after the definition of the class
template class Gene<whatever_type_u_wanna_use_t>;int
Check out these docs I found them to be super helpful.