#include <unordered_map>
#include <memory>
#include <vector>
template<> // Voxel has voxel.position which is a IVec2 containing 2 values, it also has a bool value
struct hash<Voxel> {
size_t operator()(const Voxel & k) const
{
return Math::hashFunc(k.position);
}
};
template<typename T> // This was already given
inline size_t hashFunc(const Vector<T, 2>& _key)
{
std::hash<T> hashfunc;
size_t h = 0xbd73a0fb;
h += hashfunc(_key[0]) * 0xf445f0a9;
h += hashfunc(_key[1]) * 0x5c23b2e1;
return h;
}
My main
int main()
{
Voxel t{ 16,0,true };
std::hash(t);
}
Right now i am writing on an specialisation for std::hash. Now the online submission page always returns the following errors for my code. I don't know why and what i did wrong.
error: 'hash' is not a class template struct hash<>
and
error: no match for call to '(const std::hash<Math::Vector<int, 2ul> >) (const Math::Vector<int, 2ul>&)' noexcept(declval<const_Hash((declval<const_Key&>()))>.
My own compiler only throws
error: The argument list for "class template" std :: hash "" is missing.
For posterity, I got the same error message when I had forgotten to #include <functional>.
You are specializing std::hash<> in the global namespace and this is ill-formed.
The specialization must be declared in the same namespace, std. See the example for std::hash:
// custom specialization of std::hash can be injected in namespace std
namespace std
{
template<> struct hash<S>
{
typedef S argument_type;
typedef std::size_t result_type;
result_type operator()(argument_type const& s) const
...
Related
As pointed out in the comments, my problem is actually:
template <typename T, typename U>
struct X {
static int i;
};
template <typename U>
int X<int, U>::i = 42;
with compiler error:
error: template definition of non-template 'int X<int, U>::i'
7 | int X<int, U>::i = 42;
How can I define this static member?
Original question below.
My use case is maybe a little odd:
#include <string>
#include <map>
#include <functional>
#include <memory>
template<typename ResourceType,
typename AllocatorType>
class ResourceManager
{
public:
typedef std::string IDType;
typedef std::shared_ptr<ResourceType> ResourceHandle;
typedef std::function<ResourceType(const IDType&, AllocatorType)> LoadFunc;
static ResourceHandle GetResource(const IDType& id, AllocatorType& alloc)
{
auto itr = m_resources.find(id);
if(itr != m_resources.end())
return itr->second;
ResourceHandle r
= std::make_shared<ResourceType>(m_loadFunc(id, alloc));
m_resources[id] = r;
return r;
}
static std::map<IDType, ResourceHandle> m_resources;
static LoadFunc m_loadFunc;
};
struct PretendAllocator
{
};
struct SomeResource
{
int i;
};
template<typename Allocator>
SomeResource load_some_resouce_from_file(const std::string& filename,
Allocator& alloc)
{
SomeResource x;
x.i = 12;
// let's pretend that the allocator was used and the filename was used
return x;
}
template<typename Allocator>
using SomeResourceManager = ResourceManager<SomeResource, Allocator>;
template<typename Allocator>
typename SomeResourceManager<Allocator>::LoadFunc
SomeResourceManager<Allocator>::m_loadFunc
= [](const SomeResourceManager<Allocator>::IDType& id,
Allocator& alloc)
{
return load_some_resouce_from_file(id, alloc);
}
int main()
{
// I don't know what kind of allocator I may have in real-world
PretendAllocator pretendAllocator;
// But I would use it to allocate a resource managed through Manager
SomeResourceManager<PretendAllocator>::ResourceHandle resource
= SomeResourceManager<PretendAllocator>::GetResource("some file",
pretendAllocator);
return 0;
}
This throws a bunch of compiler errors.
main.cpp|61|error: template definition of non-template 'typename ResourceManager<SomeResource, Allocator>::LoadFunc ResourceManager<SomeResource, Allocator>::m_loadFunc'|
main.cpp|62|error: invalid use of incomplete type 'SomeResourceManager<Allocator>'|
main.cpp|8|note: declaration of 'SomeResourceManager<Allocator>'|
main.cpp|68|error: expected ',' or '...' before 'int'|
main.cpp|77|error: expected ')' at end of input|
main.cpp|62|note: to match this '('|
main.cpp|77|error: expected '{' at end of input|
My use case is that I would have multiple resources which are expensive to load/acquire. So the ResourceManager has some code around it that will only call the static std::function members when absolutely required (real-world is more complex than this example).
The above seemed like the best way to do this. Basically, when defining a Resource, you would also create an alias for a ResourceManager<YourResource> but I now have the added complexity of needing to include an Allocator.
How can I get the above to compile? I'm not sure exactly what the problem is. If it's not possible, would be great to hear an alternative.
You cannot partially specialise a member without partially specialising the entire class.
Insert a partial specialisation
template <typename U>
struct X<int, U> {
static int i;
};
before the definition of i and it should work.
It is fairly standard way to declare and define a static const member of a complex type of a template class. However, I would to use SFINAE patter in my class. And that leads to this error: template definition of non-template 'const std::array<unsigned int, 2ul> Message<Self>::kData'. Removing SFINAE resolves the error.
Here is the code:
#include <iostream>
#include <type_traits>
#include <array>
using namespace std;
template <class Self, typename = std::enable_if_t<std::is_class<Self>::value>>
class Message
{
public:
bool Verify() const { return static_cast<const Self *>(this)->Verify(); }
static const std::array<uint32_t, 2> kData;
};
class Command : public Message<Command>
{
public:
bool Verify() {
std::cout << "Command::Verify";
return true;
}
};
template <class Self, typename = std::enable_if_t<std::is_class<Self>::value>>
const std::array<uint32_t, 2> Message<Self>::kData = { 12, 13 };
int main()
{
Command cmd;
cout << "Data: " << cmd.kData[0] << endl;
return 0;
}
Live code is here.
What is the proper syntax to still use SFINAE and properly define the static constant?
What is the proper syntax to still use SFINAE and properly define the static constant?
Simply using a generic type T
// ............................V
template <class Self, typename T>
const std::array<uint32_t, 2> Message<Self, T>::kData = { 12, 13 };
// .......................................^^^
Template default types/values aren't used in external definitions.
I am trying to write a template class using SFINAE to convert from a map to json and vice versa. The idea is to restrict the class to maps that have an integral value type or convertible to int, i.e. enums, but I'm having problems compiling my class.
Here's my code so far:
MapToJsonConvertor.h:
#ifndef COMMON_MAPTOJSONCONVERTOR_H_
#define COMMON_MAPTOJSONCONVERTOR_H_
#include <Poco/JSON/Object.h>
#include <Poco/JSON/Parser.h>
#include <Poco/Dynamic/Var.h>
#include <Poco/JSON/Stringifier.h>
#include <map>
#include <type_traits>
template<typename T,
typename = typename std::enable_if<std::is_convertible<T, int>::value, T>::type>
class MapToJsonConvertor
{
public:
MapToJsonConvertor(const std::map<int, T> &mapFrom): mMap(mapFrom)
{}
MapToJsonConvertor(const Poco::JSON::Object::Ptr &jsonObject): mJsonObject(jsonObject)
{}
Poco::JSON::Object::Ptr Convert(const std::string &rootName);
//std::map<int, T> Convert(const Poco::JSON::Object::Ptr &jsonObject);
private:
std::map<int, T> mMap;
Poco::JSON::Object::Ptr mJsonObject;
};
#endif /* COMMON_MAPTOJSONCONVERTER_H_ */
MapToJsonConvertor.cpp
#include "MapToJsonConvertor.h"
template<typename T>
Poco::JSON::Object::Ptr MapToJsonConvertor<T>::Convert(const std::string &rootName)
{
Poco::JSON::Object::Ptr root = new Poco::JSON::Object();
Poco::JSON::Array::Ptr array = new Poco::JSON::Array();
if (!mMap.empty())
{
for (auto &elem : mMap)
{
Poco::JSON::Object::Ptr elemPtr = new Poco::JSON::Object();
elemPtr->set("key", elem.first);
elemPtr->set("value", static_cast<int>(elem.second));
array->add(elemPtr);
}
}
root->set("elements", array);
return root;
}
The error I get is:
../src/Common/MapToJsonConvertor.cpp:12:83: error: invalid use of
incomplete type ‘class MapToJsonConvertor<T>’ Poco::JSON::Object::Ptr
MapToJsonConvertor<T>::Convert(const std::string &rootName)
^
In file included from ../src/Common/MapToJsonConvertor.cpp:9:0:
../src/Common/MapToJsonConvertor.h:21:7: note: declaration of ‘class
MapToJsonConvertor<T>’ class MapToJsonConvertor
^
I'm using the Poco libraries for Json building.
I'm still new to template metaprogramming with SFINAE, so I would appreciate some help. What am I doing wrong?
So first of all, templates should be implemented in the header file as explained here.
Besides that, your problem lies in the template signature of your function definition in your source file. You are using a 2nd template parameter in your class for SFINAE so you have to specify that template parameter in the definition as well:
template<typename T, typename U> // note the 2nd parameter
Poco::JSON::Object::Ptr MapToJsonConvertor<T, U>::Convert(const std::string &rootName)
{
...
}
I'm trying to build a small C++ example using boost fusion. However, Visual Studio 2013 gives me build errors for the following piece of code. It should simply go over a associative struct and print all member names to the console:
#include <iostream>
#include <type_traits>
#include <boost/fusion/adapted/struct/define_assoc_struct.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/algorithm/transformation/zip.hpp>
#include <boost/fusion/algorithm/transformation/transform.hpp>
namespace keys
{
struct name
{};
struct id
{};
}
BOOST_FUSION_DEFINE_ASSOC_STRUCT((), Student,
(std::string, name, keys::name)
(int, id, keys::id)
);
struct getnames
{
template<typename Sig>
struct result;
template <typename S, typename T>
struct result<getnames(S, T)>
{
typedef std::string type;
};
template<class Struct, class N>
typename result<getnames(Struct, N)>::type operator() (const N& i) const
{
return boost::fusion::extension::struct_member_name<Struct, i>::call();
}
};
struct print
{
template<typename Sig>
struct result;
template <typename T>
struct result<print(T)>
{
typedef void type;
};
template<class S>
void operator() (const S& i) const
{
std::cout << i << std::endl;
};
};
int main()
{
Student j = {"John", 42};
auto names = boost::fusion::transform(j, getnames());
boost::fusion::for_each(names, print());
return 0;
}
This is my error:
boost/fusion/view/transform_view/detail/deref_impl.hpp(38): error C2039: 'type' : is not a member of 'boost::mpl::apply<boost::fusion::detail::apply_transform_result<getnames>,const std::basic_string<char,std::char_traits<char>,std::allocator<char>> &,boost::mpl::na,boost::mpl::na,boost::mpl::na,boost::mpl::na>'
and four more errors which are coming up because of the first one.
To be honest, I am not an expert in the usage of boost fusion so maybe I simply missed something important here and someone else can help me.
There are several problems with your code.
1) In the Functor getnames, the signature of the result type and the signature of operator() are inconsistent (one takes one argument, the other takes two).
2) in the operator()(const N& i), i is a runtime variable. It cannot appear as a template parameter in the expression boost::fusion::extension::struct_member_name<Struct, i>.
I am not sure how to help without knowing what you want to do with getnames. Try to get to a consistent code first.
I want to create a hash function that is supported by template types T and E.
I use:
namespace std {
namespace tr1 {
template<class T, class E> struct hash<my_class<T, E> >
{
public:
size_t operator()(const my_class<T, E>& k) const
{
return ((hash<T>()(k.a()))^ (hash<E>()(k.x()) << 1) >> 1);
}
};
}
}
but I get errors such as:
In file included from g.cpp:1:
g.h:35: error: ‘hash’ is not a template
g.h:36: error: explicit specialization of non-template ‘hash’
g.h:76: error: ‘hash’ is not a template
g.h:76: error: ‘hash’ is not a template type
Is there no way to specialize a hash function so that it can use a template?
If not, how would I construct a hash function which is based on generic types T and E?
EDIT: Someone answered below, but not quite to my question. I am interested in being able to define a hash function which itself uses generic types. Something like hash< some_class < T > > where T is a generic type.
hash is in namespace std not in namespace std::tr1. See the snippet from en.cppreference.com for an example on how to specialize it (of course you can also partial specialize it):
#include <iostream>
#include <functional>
#include <string>
struct S
{
std::string first_name;
std::string last_name;
};
namespace std
{
template<>
struct hash<S>
{
typedef S argument_type;
typedef std::size_t value_type;
value_type operator()(argument_type const& s) const
{
value_type const h1 ( std::hash<std::string>()(s.first_name) );
value_type const h2 ( std::hash<std::string>()(s.last_name) );
return h1 ^ (h2 << 1);
}
};
}
int main()
{
S s;
s.first_name = "Bender";
s.last_name = "Rodriguez";
std::hash<S> hash_fn;
std::cout << "hash(s) = " << hash_fn(s) << "\n";
}
It's not a good idea to pollute any standard namespace with your own functions. Just put the class in your own namespace and you can do whatever you want. In your case, just make your own class API-compatible with the standard hash. Additionally, there's no problem in calling the standard hash from within your own hash.