I am receiving the following error when I attempt to compile a unit test in Visual Studio 2013:
Error 1 error C2338: Test writer must define specialization of ToString<Q* q> for your class class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> > __cdecl Microsoft::VisualStudio::CppUnitTestFramework::ToString<struct HINSTANCE__>(struct HINSTANCE__ *).
You can replicate the error by having a test method such as below:
const std::wstring moduleName = L"kernel32.dll";
const HMODULE expected = GetModuleHandle(moduleName.c_str());
Microsoft::VisualStudio::CppUnitTestFramework::Assert::AreEqual(expected, expected);
Does anyone know how I need to go about writing such a specialization of ToString?
I had the same problem when comparing class objects.
For me I could resolve it by simply writing
Assert::IsTrue(bitmap1 == bitmap2);
instead of
Assert::AreEqual(bitmap1, bitmap2);
I managed to resolve the issue by adding the following code into my unit test class file:
/* ToString specialisation */
namespace Microsoft
{
namespace VisualStudio
{
namespace CppUnitTestFramework
{
template<> static std::wstring ToString<struct HINSTANCE__>
(struct HINSTANCE__ * t)
{
RETURN_WIDE_STRING(t);
}
}
}
}
I based this on the contents of CppUnitTestAssert.h (which is where the compilation error occurs - double clicking on the compilation error will open this file for you).
Near the top of the file (and only a few lines down if you double clicked on the compilation error as noted above) you can see a set of ToString templates. I copied one of these lines and pasted it into my test class file (enclosed in the same namespaces as the original templates).
I then simply modified the template to match the compilation error (specifically <struct HINSTANCE__>(struct HINSTANCE__ * t)).
For my scenario, using RETURN_WIDE_STRING(t) is sufficient in displaying a mismatch in my AreSame assertion. Depending on the type used you could go further and pull out some other meaningful text.
As of 2021, the answer Class Skeleton provided did not work for me, but I made some modifications based on it and the following compiled. Basically the lines that follows the error message provided some examples.
template<>
inline std::wstring __cdecl Microsoft::VisualStudio::CppUnitTestFramework::ToString<MyClass>(const MyClass& t)
{
// replace with your own, here is just my example
// RETURN_WIDE_STRING(t.ToString().c_str());
}
Replace MyClass with your class.
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'm getting this error from the linker:
1>PACBalancesTest.obj : error LNK2001: unresolved external symbol "public: bool __thiscall PAC::BalChgKeyComparator::operator()(class PAC::BalChgKey const &,class PAC::BalChgKey const &)const " (??RBalChgKeyComparator#PAC##QBE_NABVBalChgKey#1#0#Z)
I must be missing something really obvious, because I've looked at the definition of the "missing" symbol repeatedly and can't see any problem.
The symbol's definition is in a .lib file. I see the following in the output from dumpbin /symbols on that .lib file:
2F0 00000000 SECTFD notype () External | ??RBalChgKeyComparator#PAC##QBE_NABVBalChgKey#1#0#Z (public: bool __thiscall PAC::BalChgKeyComparator::operator()(class PAC::BalChgKey const &,class PAC::BalChgKey const &)const )
And there are other symbols being resolved successfully from that .lib file! (In fact, from the same .obj.) [Update: I no longer think the preceding statement is true. This may be my first attempt to access any function not defined in a .h file.]
WHAT FOLLOWS IS NOT RELEVANT TO THE PROBLEM -- SO PLEASE DON'T SPEND TIME STUDYING IT!
Here's the declaration of the function (in PACBalances.h):
namespace PAC {
class BalChgKey {
public:
...
};
struct BalChgKeyComparator {
bool operator()(const BalChgKey& lhs, const BalChgKey& rhs) const;
};
typedef std::multimap<BalChgKey, long, BalChgKeyComparator> BalChgKeyLongMMap;
};
Note that I've tried changing 'struct' above to 'class', with no effect.
Here is the calling code (in a cpputest test file):
#include "CppUTest/TestHarness.h"
#include <utility>
#include <map>
#include "PACBalances.h"
using namespace PAC;
...
TEST_GROUP(PACBalanceCUMap)
{
BalChgKeyLongMMap empty;
BalChgKeyLongMMap onesy;
void setup()
{
// **Adding the following line caused this error to start to occur.**
onesy.insert(std::pair<BalChgKey, long>(BalChgKey(BOPCAT_FEE, PAYMTYPE_OVERDRAFT_FEE, 4321, 41100, 1, 17), 17));
}
void breakdown()
{
}
};
And here is the definition of the operator function itself:
bool PAC::BalChgKeyComparator::operator()(
const BalChgKey& thing1,
const BalChgKey& thing2
) const
{
if (thing1.m_balKey.m_balCat < thing2.m_balKey.m_balCat) return true;
else if (thing1.m_balKey.m_balCat > thing2.m_balKey.m_balCat) return false;
// Fall thru if balCats are equal
...
return false;
}
Please note that:
The comparator, and the typedef'd multimap, works beautifully in lots of code (not shown above).
The test file calls lots of other functions declared and defined in that .h file, but this is the first time I've tried calling a function defined in a separate .cpp file.
My question is not why does the 'onesy.insert' call requires the comparator function. I understand that. It just happens to be the first multimap operation that I've coded in the test set that actually uses the comparator.
I have various hunches, but I'm running out of them, so if someone who knows about this stuff can give me any leads I would be very grateful.
Norm
#panta rei: You provided the key in your comment. (Sorry, can't figure out how to type Greek letters here.)
The problem was basically that I didn't know how to tell Visual Studio what objects to link in. I had told my solution that AnalyticsUTest depended on AnalysticsUTested, but the linking step is performed by the project (AnalyticsUTest), not the solution, so I needed to tell the project to include this .lib file.
So I went to the project's properties sheet and created two new macros, one giving the folder where VS was putting my .lib file (ANALYTICSUTESTED_LIB_PATHS), the other giving the name of my .lib file (ANALYTICSUTESTED_LIB_DEPENDENCIES) -- both by analogy with the CPPUTEST_LIB* macros.
And then I added $(ANALYTICSUTESTED_LIB_PATHS) to Linker > General > Additional Library Directories. And I added $(ANALYTICSUTESTED_LIB_DEPENDENCIES) to Linker > Input > Additional Dependencies.
And that fixed my problem! (I've spelled it out here in case another newbie like me comes along and needs it.)
Thank you, panta rei. How do I give you points for an answer provided via a comment?
I'm facing an interesting problem: I had an MFC application project in Visual C++ 6.0. Since there are many changes either in MFC or in C++ standard, I wanted to port my application to Visual Studio 2010. It was fine, but I am facing a warning now, which I can't handle.
The header file has the following class definition:
template <class T>
class foo : public CObject
{
// ...
// other stuff
// ...
private:
CTypedPtrMap<CMapWordToPtr, const long, T*> oElementMap;
void some_stuff();
}
In the source file there is:
template <class T>
void foo::some_stuff()
{
// ...
// other stuff
// ...
int nIndex = 0;
// ...
// other stuff
// ...
oElementMap.RemoveKey(nIndex);
}
When I try to compile this, I get the following warnings:
Warning 1 warning C4244: 'argument' : conversion from 'const long' to
'WORD', possible loss of data c:\programme\microsoft visual studio
10.0\vc\atlmfc\include\afxtempl.h 2066
It comes definetly from the above mentioned "RemoveKey" line: if I just simply comment out that line, I won't get this warning.
I know, the main problem is, that CTypedPtrMap object uses const long as key type, but CMapWordToPtr would have WORD (unsigned short) instead of it. But the fact is: I need const long as key type, since I am processing regulary about 1 million data entries in this map, so with unsigned short the class would not be capable to do it's job furthermore.
I tried to nest either the "RemoveKey" line or the include of stdafx.h into the following expressions, but neither worked:
#pragma warning (disable: 4244)
// expression
#pragma warning (default: 4244)
Please share me any ideas about this issue, how could I resolve this warning WITHOUT changing the container's oElementMap definition and behaviour, and WITHOUT supress/disable this warning globally in the project settings as well as WITHOUT changing the afxtempl.h file supplied by VS2010.
Thanks for help:
Andrew
I've replaced it's definition to: CMap<long, long&, T*, T*&> oElementMap;. I was not sure it is the "long-counterpart" of the old map definition, therefore I did several test to compare them.
The solution was finally this.
I was getting the following error from Visual Studio:
error LNK2019: unresolved external symbol "public: __thiscall BSTree::BSTreeNode::BSTreeNode(class TestData const &,class BSTree::BSTreeNode *,class BSTree::BSTreeNode *)" (??0BSTreeNode#?$BSTree#VTestData##H##QAE#ABVTestData##PAV01#1#Z) referenced in function "protected: void __thiscall BSTree::insertHelper(class TestData const &,class BSTree::BSTreeNode * &)" (?insertHelper#?$BSTree#VTestData##H##IAEXABVTestData##AAPAVBSTreeNode#1##Z)
Here are the functions that the compiler brings into question:
template < typename DataType, class KeyType >
BSTree<DataType,KeyType>::BSTreeNode::BSTreeNode ( const DataType &nodeDataItem,
BSTreeNode *leftPtr, BSTreeNode *rightPtr ) {
left = leftPtr;
right = rightPtr;
dataItem = nodeDataItem;
}
template < typename DataType, class KeyType >
void BSTree<DataType,KeyType>::insertHelper (const DataType& d, BSTreeNode*& b) {
if (b == 0) {
b = new BSTreeNode(d, 0, 0);
}
else if (d.getKey() < b->dataItem.getKey()) {
insertHelper(d, b->left);
}
else if (d.getKey() > b->dataItem.getKey()) {
insertHelper(d, b->right);
}
else {
b->dataItem = d;
}
}
So I look them over and I believe my code looks correct. So I perform a rebuild and then there are no errors and the program fires up just fine. I asked my lab instructor about why this occurs, but he said that he did not have a suitable answer. This is something that I've seen more and more while my projects are becoming more complex.
I've done some research:
Difference between build, rebuild, and clean solution
Do I always need to Clean/Rebuild?
Is this something that just inevitably happens while working with the Visual Studio IDE? Is there anything that I can do to prevent this? Are there any consequences from having this issue come up (ie. is there a flaw in my code)?
UPDATED: It seems that this might be the cause for much of the linker errors that I've been witnessing the semester.
Here is the advice from a book:
"Compiling programs that use templated classes requires a change in what files are included using the #include preprocessor directive, and in how the program is compiled. Because of how C++ compilers process templated code, the program that creates objects of the classes (e.g., main.cpp) must include the class implementation file, not the class declaration file. That is, it must do #include "Classname.cpp" instead of the usual #include "Classname.h" The rule is in effect the rest of this book. Because the main implementation file does a #include of the class implementation code, the class implementation code is not compiled separately."
I have a problem with generics in c++.I have two Matrix.h and Matrix.cpp files.Here is files:
#pragma once
template<class T>
class Matrix
{
public:
static T** addSub(int size,T** firstMatrix,T** secondMatrix,int operation);
}
and Matrix.cpp
#include "Martix.h"
template<class T>
static T** Matrix<T>::addSub( int n,T **firstMatrix,T **secondMatrix,int operation)
{
//variable for saving result operation
T **result = new T*[n];
//create result matrix
for( int i=0;i<n;i++)
result[i] = new T[n];
//calculate result
for( int i=0;i<n;i++)
for(int j=0;j<n;j++)
result[i][j] =
(operation == 1) ? firstMatrix[i][j] + secondMatrix[i][j]:
firstMatrix[i][j] - secondMatrix[i][j];
return result;
}
when I run these I get the below error:
Error 1 error LNK2019: unresolved external symbol "public: static int * * __cdecl Matrix<int>::addSub(int,int * *,int * *,int)" (?addSub#?$Matrix#H##SAPAPAHHPAPAH0H#Z) referenced in function "public: static int * * __cdecl Matrix<int>::strassenMultiply(int,int * *,int * *)" (?strassenMultiply#?$Matrix#H##SAPAPAHHPAPAH0#Z) C:\Users\ba.mehrabi\Desktop\Matrix\matrixMultiplication\main.obj matrixMultiplication
what is the problem?
Unfortunately, you can't have the declaration of a template class in the *.cpp files. The full definition has to stay in the header file. This is a rule of many C++ compilers.
See this: http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12
A template is not a class or a function. A template is a "pattern"
that the compiler uses to generate a family of classes or functions.
In order for the compiler to generate the code, it must see both
the template definition (not just declaration) and the specific
types/whatever used to "fill in" the template. For example, if you're
trying to use a Foo, the compiler must see both the Foo template
and the fact that you're trying to make a specific Foo.
Your compiler probably doesn't remember the details of one .cpp
file while it is compiling another .cpp file. It could, but most do
not and if you are reading this FAQ, it almost definitely does not.
BTW this is called the "separate compilation model."
The link has a workaround, but keep in mind that a template is a glorified macro so the header file is probably the best place for it.
The poster of this SO post shows a demonstration of the workaround.
First of all, the definition of functions of a class template, should go in the header itself.
Second, if you define the static member function out of class (though in the header itself), then don't use the static keyword (in the definition). It only needed in the declaration only.
Add
template Matrix<int>;
at the end of your cpp file and it will work. But you need to learn a few things about templates, otherwise you'll have to deal with lots of issues you don't understand.