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.
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 trying to build google v8 using visual studio 2019(i'm able to build using official steps with clang), and got below error:
Error C2027 use of undefined type “v8::internal::Object" v8_base_without_compiler E:\v8\src\handles\handles.h 144
V8_INLINE T operator*() const {
// unchecked_cast because we rather trust Handle<T> to contain a T than
// include all the respective -inl.h headers for SLOW_DCHECKs.
SLOW_DCHECK(IsDereferenceAllowed(INCLUDE_DEFERRED_CHECK));
return T::unchecked_cast(Object(*location())); // error on this line
}
my understanding of this part is, handles.h includes objects.h and has forward declaration for class Object (from objects.h), and inline operator method is calling Object constructor, which leads to c2027 use of undefined type v8::internal::Object
i created a simple c++ project with visual studio 2019 to reproduce the same error message
handles.h
#ifndef HANDLES_H_
#define HANDLES_H_
// forward declaration
class Object;
class Handle {
public:
__forceinline void* op() {
return new Object(0); // error here c2027 use of undefined type "Object"
}
void dummy();
};
#endif
objects.h
#ifndef OBJECTS_H_
#define OBJECTS_H_
class Object {
public:
explicit Object(int n):_n(n) {
}
void dummy();
int _n;
};
#endif
which is similar logic, an inline method implementation calls another class constructor
i don't understand how google's official steps with gn and clang could compile through the whole project, but msvc errors out
how to make it work for visual studio 2019? thanks!
I'm copying #JVApen's comment as answer
add #include "ojbects.h" will fix the issue
and if you're trying to build google's v8 using visual studio 2019, add #include "objects/objects.h" in handles/handles.h, then it will compile through
I'm now dealing with template in c++ with PCL (Point Cloud Library) and I encountered something that I'm not able to solve (I searched before on the internet and on Stack)
I have a template class called Features.
my hpp file:
#ifndef KeyFeatures_hpp
#define KeyFeatures_hpp
// Declarations and includes
typedef pcl::PointXYZRGB PointTypeRGB;
template<typename FeatureType>
class Features {
public:
Features(const int typeDescriptor);
void setDescriptorExtractor(typename pcl::Feature<PointTypeRGB, FeatureType>::Ptr extractor);
private:
typename pcl::Feature<PointTypeRGB, FeatureType>::Ptr m_descriptor_extractor;
};
#endif /* Features_hpp */
In the cpp file I have a constructor which will checks what kind of type is it and then perform some action.
template <typename FeatureType>
Features<FeatureType>::Features(const int type){
//Some code
if (type == DESCRIPTOR_SHOT){
pcl::SHOTEstimationOMP<PointTypeRGB, pcl::Normal, pcl::SHOT352>* shot = new pcl::SHOTEstimationOMP<PointTypeRGB, pcl::Normal, pcl::SHOT352>;
shot->setRadiusSearch (0.02f);
pcl::Feature<PointTypeRGB, pcl::SHOT352>::Ptr descriptor_extractor (shot);
descriptor_extractor->setSearchMethod (pcl::search::Search<PointTypeRGB>::Ptr (new pcl::search::KdTree<PointTypeRGB>));
this->m_descriptor_extractor = descriptor_extractor;//ERROR
setDescriptorExtractor(descriptor_extractor);//ERROR
// Some code
}
The error appeared in the last two lines when I try without success to fill in my variable member.
Each time I have the following error x 10 (corresponding to my 10 kind of type)
error: no matching conversion for functional-style cast from 'const shared_ptr<pcl::Feature<pcl::PointXYZRGB, pcl::SHOT352> >'
to 'this_type' (aka 'shared_ptr<pcl::Feature<pcl::PointXYZRGB, pcl::ShapeContext1980> >')
However at the end of my cpp file I put all my template class. For example:
template class Features<pcl::SHOT352>;
In my main function I called this class by using:
Features<pcl::SHOT352> feature_SHOT(type);
It seems that it's not able to perform the conversion..
Can someone might be able to help me ?
Thank
Apparently you are instantiating Features<pcl::ShapeContext1980> so its m_descriptor_extractor has the type pcl::Feature<pcl::PointXYZRGB, pcl::ShapeContext1980>::Ptr which is shared_ptr<pcl::Feature<pcl::PointXYZRGB, pcl::ShapeContext1980>>.
But inside the constructor you are still using pcl::Feature<pcl::PointXYZRGB, pcl::SHOT352>::Ptr, that is shared_ptr<pcl::Feature<pcl::PointXYZRGB, pcl::SHOT352>> - a totally different type.
And as a side note, you generally don't implement templates in .cpp files.
Firstly, the official term is a "class template" - a template for creating classes.
You appear to have created a class called Features<pcl::ShapeContext1980>.
This has m_descriptor_extractor of type shared_ptr<pcl::Feature<pcl::PointXYZRGB, pcl::ShapeContext1980> >
You are trying to assign a shared_ptr<pcl::Feature<pcl::PointXYZRGB, pcl::SHOT352>> to it.
They are completely unrelated types, so it fails at compile time.
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.
If I instantiate a mapped_file_source (boost 1.46.1 ) with a narrow character string as in the following I don't have a problem:
boost::iostreams::mapped_file_source m_file_( "testfile.txt" );
However if I try to use a wide string:
boost::iostreams::mapped_file_source m_file_( L"testfile.txt" );
I get the following compiler error in VC2010 SP1:
P:\libs\boost_1_46_1\boost/iostreams/device/mapped_file.hpp(128): error C2248: 'boost::iostreams::detail::path::path' : cannot access private member declared in class 'boost::iostreams::detail::path'
P:\libs\boost_1_46_1\boost/iostreams/detail/path.hpp(111) : see declaration of 'boost::iostreams::detail::path::path'>
P:\libs\boost_1_46_1\boost/iostreams/detail/path.hpp(37) : see declaration of 'boost::iostreams::detail::path'
If I instead try to pass the constructor a boost::filesystem::path I get the following error:
P:\libs\boost_1_46_1\boost/iostreams/device/mapped_file.hpp(128): error C2664: 'boost::iostreams::detail::path::path(const std::string &)' : cannot convert parameter 1 from 'const boost::filesystem3::path' to 'const std::string &'
Reason: cannot convert from 'const boost::filesystem3::path' to 'const std::string'
I feel like I'm missing something obvious, but I'm just running around in circles trying to figure out what the compiler is trying to tell me, but I'm just getting lost. That palm to forehead moment is just not happening.. What is it that I am doing incorrectly?
The constructor defined in mapped_file.hpp looks like the following:
// Constructor taking a parameters object
template<typename Path>
explicit mapped_file_source(const basic_mapped_file_params<Path>& p);
The basic_mapped_file_params class constructors look like this:
// Construction from a Path
explicit basic_mapped_file_params(const Path& p) : path(p) { }
// Construction from a path of a different type
template<typename PathT>
explicit basic_mapped_file_params(const PathT& p) : path(p) { }
Where the template class is defined as:
// This template allows Boost.Filesystem paths to be specified when creating or
// reopening a memory mapped file, without creating a dependence on
// Boost.Filesystem. Possible values of Path include std::string,
// boost::filesystem::path, boost::filesystem::wpath,
// and boost::iostreams::detail::path (used to store either a std::string or a
// std::wstring).
template<typename Path>
struct basic_mapped_file_params
: detail::mapped_file_params_base
{
There is some additional help in the header that says:
// For wide paths, instantiate basic_mapped_file_params
// with boost::filesystem::wpath
If I take this approach with:
boost::iostreams::basic_mapped_file_params<boost::filesystem::wpath> _tmp(L"test.txt");
boost::iostreams::mapped_file_source m_file_( _tmp );
I get the same C2664 error mentioned above..
I know the compiler is telling me what the problem is, but looking at the header source and the comments leads me to believe that what I'm trying to accomplish is supported, it's just my approach that is incorrect. Am I misinterpreting what the header file is telling me? I know there is probably a good lesson about template instantiation and explicit/implicit conversion in here somewhere.
Interestingly enough, upgrading my boost install to 1.47.0 seems to cleared up C2664 error but I'm still getting the C2248 error about access to the private member.
With boost 1.48 I can do something like this.
#include <boost/filesystem.hpp>
#include <boost/iostreams/device/mapped_file.hpp>
#include <iostream>
int main()
{
boost::filesystem::path p(L"b.cpp");
boost::iostreams::mapped_file file(p); // or mapped_file_source
std::cout << file.data() << std::endl;
}
or you can do this with mapped_file_params(used create new file)
boost::filesystem::path p(L"aa");
basic_mapped_file_params<boost::filesystem::path> param; // template param
param.path = p;
param.new_file_size = 1024;
It's telling you that boost::iostreams::mapped_file_source's constructor does not take a wchar_t*, nor does it take a boost::filesystem::path. It only takes std::string, or types convertible to std::string. Or, to put it another way, you can't use UTF-16 paths with this object.
It looks like the documentation for mapped_file is pretty old and does not reflect what is in the header or in the header comments. In order to instantiate a boost::iostreams:mapped_file_source object with a wide character string you need to explicity pass in the boost::iostreams::detail::path like this:
boost::iostreams::mapped_file_source m_file_( boost::iostreams::detail::path(boost::filesystem::path(L"testfile.txt")) );
I was able to get this to compile by stepping thought the error messages and determining how the template classes were being instantiated and finally saw that boost::iostreams::detail::path had a private constructor that took a &std::wstring as a parameter which is where the code was failing to compile.