I am trying to compile solutions and projects on MSVC++ 10 that worked fine in MSVC++ 9, and I am having trouble with it, mostly getting the following message:
error C2888: 'std::hash' : symbol cannot be defined within namespace 'tr1'
on the following code:
namespace std {
namespace tr1 {
template <>
struct hash< Rubedo::eChannelFamily >
{
std::size_t operator()( const Rubedo::eChannelFamily& Key ) const
{
return ( int ) Key;
}
};
}}
I would be perfectly happy if I could do one of the following:
Modify the code to fix the bugs and compile cleanly;
Force the compiler to behave like MSVC++ 9.0.
How would I do something like that?
Thank you very much in advance.
hash is in namespace std in VS2010, as it's part of C++0x's Standard library, not std::tr1. Just remove the tr1 section and the compiler should be fine.
template<> class std::hash< Rubedo::eChannelFamily >>
: public std::unary_function<const Rubedo::eChannelFamily, size_t>
{
public:
size_t operator()(const Rubedo::eChannelFamily& ref) const {
return ( int ) ref;
}
};
This is a fairly trivial modification of a hash I have for my own type which compiles successfully.
You've to inherit unary_function like this and tr1 is not needed anymore,
namespace std
{
template <>
struct hash<Rubedo::eChannelFamily> : public unary_function<Rubedo::eChannelFamily, size_t>
{
size_t operator()(const Rubedo::eChannelFamily& key) const
{
return (size_t) key;
}
};
}
Related
I am trying to convert boost::object_pool usage on my old project to new visual studio 2019 project, I am using boost version 1.56
ObjectPool.h
class BOOST_OBJECT_POOL_CHECKER
{
boost::object_pool< T > m_sObjectPool;
template <class Arg1>
T* contruct(Arg1& sArg1)
{
T* temp = m_sObjectPool.construct(sArg1);
return temp;
}
}
MaterialServer.h
class MaterialServer
{
MaterialServer(dword serviceType, std::string path);
Material* NEW_MATERIAL();
}
Material.h
class Material
{
BOOST_OBJECT_POOL_CHECKER<Material> m_poolMATERIAL;
Material(MaterialServer* pMatServer);
}
Material.cpp
Material* MaterialServer::NEW_MATERIAL()
{
//Material* returnMaterial = m_poolMATERIAL.construct(this); << error on vs2019, not correct parameter
Material* returnMaterial = m_poolMATERIAL.construct(*this);
}
got first error
boost_1_56\boost\pool\detail\pool_construct_simple.ipp(19,1): error C2664: 'Material::Material(MaterialServer*)': cannot convert argument 1 from 'const T0' to 'MaterialServer *'
ObjectPool.h(68): message : see reference to function template instantiation 'Material *boost::object_pool<T,boost::default_user_allocator_new_delete>::construct<Arg1>(const T0 &)' being compiled
with
[
T=Material,
Arg1=MaterialServer,
T0=MaterialServer
]
should I need upgrade boost version? because previously this code compiled fine on vs2008, but not compiled on vs2019, this c++11 standard so confusing for me
can I get explanation this behavior?
Frankly, this code cannot have compiled under any compiler.
Note: I'm ignoring numerous typos, omitted semi-colons, omitted template declarators, typedefs and access specifiers to focus on the real issues.
You're passing *this which is Material&. However, the contruct [sic] function takes a MaterialServer*.
So, in fact, the commented line was closer, and makes sense IFF it were a member of MaterialServer, not Material.
It would make a lot more sense, logically, for the material server to "create new materials", anyways, and almost works:
class Material {
public:
Material(MaterialServer* pMatServer);
};
class MaterialServer {
BOOST_OBJECT_POOL_CHECKER<Material> m_poolMATERIAL;
public:
MaterialServer(dword serviceType, std::string path);
Material* NEW_MATERIAL();
};
Material* MaterialServer::NEW_MATERIAL()
{
Material* returnMaterial = m_poolMATERIAL.construct(this);
return returnMaterial;
}
I say /almost/ because construct takes its argument by mutable reference. That won't compile here (this is NOT a mutable lvalue).
So, fixing that:
template <typename Arg1> T* construct(Arg1 sArg1) {
return m_sObjectPool.construct(sArg1);
}
Or, more generically:
template <typename... Arg> T* construct(Arg&&... sArg) {
return m_sObjectPool.construct(std::forward<Arg>(sArg)...);
}
We get "compiling code". We can't link it (the constructors aren't defined).
Adding some more imagined code:
Live On Coliru
#include <boost/pool/object_pool.hpp>
#include <iomanip>
#include <iostream>
#include <string>
#include <atomic>
using dword = uint32_t;
template <typename T> class BOOST_OBJECT_POOL_CHECKER {
boost::object_pool<T> m_sObjectPool;
public:
template <typename... Arg> T* construct(Arg&&... sArg)
{
return m_sObjectPool.construct(std::forward<Arg>(sArg)...);
}
};
class MaterialServer; // forward declare
class Material {
public:
Material(MaterialServer* pMatServer);
};
class MaterialServer {
BOOST_OBJECT_POOL_CHECKER<Material> m_poolMATERIAL;
dword _serviceType;
std::string _path;
public:
MaterialServer(dword serviceType, std::string path)
: _serviceType(serviceType)
, _path(path)
{
}
Material* NEW_MATERIAL();
dword getServiceType() const { return _serviceType; }
std::string_view getPath() const { return _path; }
};
Material* MaterialServer::NEW_MATERIAL()
{
Material* returnMaterial = m_poolMATERIAL.construct(this);
return returnMaterial;
}
Material::Material(MaterialServer* pMatServer)
{
static std::atomic_int id{0};
std::cout << "Material " << id++ << " from server ("
<< pMatServer->getServiceType() << ", "
<< std::quoted(pMatServer->getPath()) << ")\n";
}
int main() {
MaterialServer a(123, "Material/a/resource");
MaterialServer b(234, "Material/b/resource");
a.NEW_MATERIAL();
a.NEW_MATERIAL();
b.NEW_MATERIAL();
a.NEW_MATERIAL();
}
Prints
Material 0 from server (123, "Material/a/resource")
Material 1 from server (123, "Material/a/resource")
Material 2 from server (234, "Material/b/resource")
Material 3 from server (123, "Material/a/resource")
The following code snippet compiles just fine with GCC 9.1 and Clang 6.0 under C++11/14/17 standards, but refuses to compile with Visual Studio 2019. I can change the return of getDummies() to auto and VS will compile with C++14/17 standards, but this breaks C++11 compatibility on all compilers, which I need to keep.
#include <cstdlib>
#include <utility>
template<typename T>
class Dummy
{
public:
//static auto getDummies() // Works but breaks C++11 compatibility
static std::pair<Dummy<int>, Dummy<int>> getDummies()
{
return std::make_pair(Dummy<int>{}, Dummy<int>{});
}
};
int main()
{
auto dummies = Dummy<int>::getDummies(); // Error C2079
return EXIT_SUCCESS;
}
The class Dummy is not fully defined at the point that the getDummies() function is defined, inside the class.
You can declare the function in the class then define it outside the class, like:
template<typename T>
class Dummy
{
public:
static std::pair<Dummy<int>, Dummy<int>> getDummies();
};
template<typename T>
std::pair<Dummy<int>, Dummy<int>> Dummy<T>::getDummies()
{
return std::make_pair(Dummy<int>{}, Dummy<int>{});
}
I'm trying to implement a simple system using template struct, the code is very simple and compile fine with MSVC, yet i cannot understand why CLANG gives me this error: "lld-link : error : undefined symbol: public: static struct FMyStruct const TSpec<1>::m_struct"
I compile on a windows 64bitmachine with VisualStudio IDE but CLANG LLVM as compiler. The code works fine with MSVC.
I simplified my problem to the very minimum, i tried to put everything in one single cpp file, with no result. I also tried explicit template instanciation.
I want to be compliant with C++14, no C++17. One thing i tried that worked was declaring the m_struct member as an inline variable, but then i get this warning: "inline variables are a C++17 extension"
struct FMyStruct
{
const int _p0;
const int _p1;
const int _p2;
};
template< int > struct TSpec {
static constexpr FMyStruct m_struct = { 0, 0, 0 };
};
FMyStruct
Function( int i )
{
return TSpec< 1 >::m_struct;
}
int main()
{
return 0;
}
Result:
"lld-link : error : undefined symbol: public: static struct FMyStruct const TSpec<1>::m_struct"
I expect the linker to find the symbol m_struct since it is defined very next to it ...
The weirdest part is that if i try:
int
Function( int i )
{
return TSpec< 1 >::m_struct._p0;
}
the program will compile fine.
Edit: My CLANG version is 9.0.0, prebuilt distributed version for windows from the official website.
clang version 9.0.0 (trunk)
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files\LLVM\bin
It indeed seems to be a bug related to the CLANG version, thanks #Sombrero Chicken for pointing this out.
So this is definitely weird but i managed to solve this avoiding the C++17-specific 'inline' declaration of the static member by adding this after the template struct definition:
template< int N > const FMyStruct TSpec< N >::m_struct;
By the way, it does not seem to be related to the template declaration at all.
For summary, it gives this program that will compile fine.
struct FMyStruct
{
const int _p0;
const int _p1;
const int _p2;
};
template< int > struct TSpec {
static constexpr FMyStruct m_struct = { 0, 0, 0 };
};
template< int N > const FMyStruct TSpec< N >::m_struct;
FMyStruct
Function( int i )
{
return TSpec< 1 >::m_struct;
}
int main()
{
return 0;
}
I still do not really understand why this is necessary since the static member is public to the struct, and part of the same unit & file; i guess this is a different matter but i'd like to be enlightened. Thank you.
As requested, I have a code file that compiles and runs on cygwin, but not in MSVS where an empty initalizer being used as a parameter to a templated function is okay in gcc, but not MSVS:
// TestError.cpp : Defines the entry point for the console application.
//
#include <iostream>
#include <array>
#include <vector>
template <typename T>
class otherclass
{
public:
T* allocated;
otherclass(int n) { allocated = new T[n]; }
~otherclass() { delete[] allocated; }
};
class otherclass_accessor
{
public:
int sz;
otherclass_accessor(int inputSize) : sz(inputSize) {}
};
template<typename T>
class baseclass : public otherclass_accessor
{
private:
std::vector<T*> mPointers;
public:
T const * const * sp;
std::vector<T> someVector;
baseclass(std::vector<T>& someVector) : otherclass_accessor(someVector) {}
~baseclass() { mPointers.resize(0); }
};
class RRC : public baseclass<int>
{
public:
template <typename T> RRC(otherclass<T>& a) : baseclass<void>(reinterpret_cast<otherclass<void>&>(a)) {}
template< typename T > operator baseclass<T> const & () const { return reinterpret_cast< baseclass<T> const & >(*this); }
};
template< int N > using ARRC = std::array<RRC, N>;
template <int A>
void run_filter_multi(ARRC<A> in)
{
std::cout << "Input Size:" << in.size() << std::endl;
}
int main()
{
run_filter_multi<0>({});
return 0;
}
compiles with g++ -std=c++11 TestError.cpp -o test
and outputs:
Input Size:0
but with MSVS2017 I get error C2664:
1>------ Build started: Project: TestError, Configuration: Debug Win32 ------
1>TestError.cpp
1>c:\users\dayd\documents\visual studio 2017\projects\testerror\testerror.cpp(53): error C2664: 'void run_filter_multi<0>(std::array)': cannot convert argument 1 from 'initializer list' to 'std::array'
1>c:\users\dayd\documents\visual studio 2017\projects\testerror\testerror.cpp(53): note: Invalid aggregate initialization
1>Done building project "TestError.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
So - now my question is why is an empty initializer okay with g++, but not MSVS2017? This is a watered down version where I tried to mock up what I was experiencing in a much larger project I am trying to make "cross platform". I can't seem to think of a way around it in MSVS. I have tried using std::vector instead of std::array, but the std::array is so pervasive in the code I inherited that trying to change all the underlying layers would be very painful, at best.
Thanks!
There are a few issues, but the big show-stopper one is this:
#include <array>
struct S { S(int); }; // Not default-constructible.
std::array<S, 0> x {};
This fails with
error C2073: 'std::array<S,0>::_Elems': elements of partially initialized array must have a default constructor
Since C++ doesn't allow for zero-length arrays, but std::array<T, 0> is still supposed to work, it must be implemented using a little bit of trickery. Unfortunately MSVC's trickery is broken: it gives it a field of type T[1], which then fails badly because the empty unused T element cannot be constructed.
The only ways around this that I see is giving RRC a default constructor, or avoiding std::array<T, 0>.
#include <iostream>
#include <memory>
template<typename T>
class Test: public std::enable_shared_from_this< Test<T> >
{
public:
std::shared_ptr< Test<T> > getMe()
{
return shared_from_this();
};
};
int main(int argc, const char * argv[])
{
Test<int> aTest;
return 0;
}
When i try to compile this on Xcode 5 i get
Use of undeclared identifier 'shared_from_this'
I tested it and its working on Visual Studio 2010.
return this->shared_from_this();
^^^^^^
VC++ 2010 does not implement the lookup rules for templated base classes exactly correctly. The clang behavior is correct. The above fix will make it work on both your platforms.