So, I had a simple working code, for example
template <typename T, typename VALUE>
VALUE mapAt(T key)
{
std::map<T, VALUE>::const_iterator item_i(MyMap.find(key))
, end_i(MyMap.end());
if (item_i == end_i)
{
throw std::exception("No such key!");
}
return (*item_i).second;
}
Question: is it possible to create a new template function without using std::map, but using different containers (e.x. std::map, std::multimap, ...), something like this:
template <class Container, typename T, typename VALUE>
VALUE mapAt(Container& MyMap, T key)
{
Container<T, VALUE>::const_iterator item_i(MyMap.find(key))
, end_i(MyMap.end());
/* ... */
}
Problem: when i'm tring to use it, like:
std::map<int, char> my_map;
char ch = mapAt<std::map<int, char>(), int, char>(my_map, 123); // C2664 error
compiler gaves me an error:
main.cpp(119) : error C2664: 'mapAt' :
cannot convert parameter 1 from
'std::map<_Kty,_Ty>' to
'std::map<_Kty,Ty> (_cdecl &)' 1>
with 1> [ 1>
_Kty=int, 1> _Ty=char 1> ] 1> No user-defined-conversion
operator available that can perform
this conversion, or the operator
cannot be called
You can write something like this:
template <class Container>
typename Container::mapped_type mapAt(Container& MyMap, typename const Container::key_type& key)
{
typename Container::const_iterator iter = MyMap.find(key);
return iter->second;
}
int main()
{
std::map<int, char> my_map;
char ch = mapAt(my_map, 123);
}
Related
I'm trying to use a variant's visitor for multiple types and then generating a new random value. Be aware that I can't use more recent compiler than Visual Studio 2015 Update 3 and GCC 4.9 because of reasons out of my control.
Here is what I have
std::random_device randomDevice;
std::mt19937 randomEngine(randomDevice());
typedef mpark::variant< // Implementation of std::variant for C++11,14
bool,
int8_t, uint8_t,
int16_t, uint16_t,
int32_t, uint32_t,
int64_t, uint64_t,
float, double,
std::string
> VariantValue;
struct ValueVisitor
{
ValueVisitor(VariantValue* pNewVal)
: pNewVal(pNewVal) {}
void operator()(const std::string & s) const
{
// Generate some random string into *pNewVal
}
void operator()(const bool& t) const
{
*pNewVal = !t;
}
template <typename T,
std::enable_if_t<std::is_integral<T>::value>* = nullptr,
std::enable_if_t<!std::is_same<T, bool>::value>* = nullptr>
>
void operator()(const T& t) const
{
std::uniform_int_distribution<T> dist
(
std::numeric_limits<T>::lowest(),
std::numeric_limits<T>::max()
);
*pNewVal = dist(randomEngine);
}
template <typename T, typename std::enable_if<
std::is_floating_point<T>::value>::type* = nullptr>
void operator()(const T& t) const
{
std::uniform_real_distribution<T> dist
(
std::numeric_limits<T>::lowest(),
std::numeric_limits<T>::max()
);
*pNewVal = dist(randomEngine);
}
VariantValue* pNewVal;
};
VariantValue vSource {(double)12 };
VariantValue vTarget;
ValueVisitor valueVisitor(&vTarget);
mpark::visite(valueVisitor, v);
But I'm getting the error C2338 invalid template argument for uniform_int_distribution.
Looking at output window for more details
1>c:\program files (x86)\microsoft visual studio 14.0\vc\include\random(2387): error C2338: invalid template argument for uniform_int_distribution
1> d:\project\xxx.cpp(271): note: see reference to class template instantiation 'std::uniform_int_distribution<T>' being compiled
1> with
1> [
1> T=int8_t
1> ]
1> d:\project\3rdparty\mpark\include\mpark\lib.hpp(237): note: see reference to function template instantiation 'void ValueVisitor::operator ()<T,void>(const T &) const' being compiled
1> with
1> [
1> T=int8_t
1> ]
...
So, If I well understood, it seems that when T=bool the functor's function targeted is the one for is_integral. But why ? I explicitly removed the bool type with std::enable_if_t<!std::is_same<T, bool>::value>* = nullptr.
I tried a different approaches like
template <typename T>
void operator()(const T & t)
{
if (std::is_same<T, bool>::value) {
} else if (std::is_floating_point<T>::value) {
} else if (std::is_integral<T>::value) {
} else if (std::is_same<T, std::string>::value) {
}
But without success, it's worst as now the float variation are still trying to use the uniform_int_distribution.
I'm really out of idea.
Best regards,
I'm trying to make a manager, which provides access via templates to containers that store different types of data.
First of all, i made base manager class for storing different type of data
template <typename T>
class BaseMapManager{
public:
T add(T element, std::string name);
T remove(T element);
T remove(std::string name);
T remove(unsigned int id);
T get(std::string name);
T get(unsigned int id);
BaseMapManager() { id = 0; };
~BaseMapManager() { nameMap.clear(); idMap.clear(); };
protected:
std::map<std::string, T> nameMap;
std::map<unsigned int, T> idMap;
//each element of type T gets new unique id
unsigned int id;
//hide it
BaseMapManager(const BaseMapManager&) {};
BaseMapManager& operator=(const BaseMapManager&) {};
};
Then i made my concrete manager, which had to store 3 types of baseMapManagers:
class ResourceManager{
public:
//creates singleton
static ResourceManager* init(){
static ResourceManager singleton;
return &singleton;
}
template <typename T>
void load_resource(std::string path, std::string name){
get_map<std::shared_ptr<T>>().add(std::shared_ptr<T>(new T(path, name), name);
}
template <typename T>
std::shared_ptr<T> get_resource(std::string name){
get_map<T>().get(name);
}
template <typename T>
std::shared_ptr<T> get_resource(unsigned int id){
get_map<T>().get(id);
}
private:
BaseMapManager<std::shared_ptr<AnimationResource> > animationMap;
BaseMapManager<std::shared_ptr<ImageResource> > imageMap;
BaseMapManager<std::shared_ptr<FontResource> > fontMap;
template <typename T>
BaseMapManager<T>& get_map(){
if (std::is_same<T, std::shared_ptr<AnimationResource> >() == true) return animationMap;
if (std::is_same<T, std::shared_ptr<ImageResource> >() == true) return imageMap;
if (std::is_same<T, std::shared_ptr<FontResource> >() == true) return fontMap;
};
};
and now i got this:
1>------ Build started: Project: BOSS, Configuration: Debug Win32 ------
1> main.cpp
1>d:\programming\github projects\boss\boss\new\resourcemanager\resourcemanager.h(43):
error C2440: 'return' : cannot convert from 'BaseMapManager<T>' to 'BaseMapManager<T> &'
1> with
1> [
1> T=std::shared_ptr<ImageResource>
1> ]
1> and
1> [
1> T=std::shared_ptr<AnimationResource>
1> ]
1> d:\programming\github projects\boss\boss\new\resourcemanager\resourcemanager.h(21) : see reference to function template instantiation 'BaseMapManager<T> &ResourceManager::get_map<std::shared_ptr<_Ty>>(void)' being compiled
1> with
1> [
1> T=std::shared_ptr<AnimationResource>,
1> _Ty=AnimationResource
1> ]
1> d:\programming\github projects\boss\boss\new\main.cpp(17) : see reference to function template instantiation 'void ResourceManager::load_resource<AnimationResource>(std::string,std::string)' being compiled
1>d:\programming\github projects\boss\boss\new\resourcemanager\resourcemanager.h(44): error C2440: 'return' : cannot convert from 'BaseMapManager<T>' to 'BaseMapManager<T> &'
1> with
1> [
1> T=std::shared_ptr<FontResource>
1> ]
1> and
1> [
1> T=std::shared_ptr<AnimationResource>
1> ]
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
The goal is - providing access to different types on data using template functions like
manager->get_resource<AnimationResource>(itsName) //get it or
manager->load_resource<FontResource>(itsPath, itsName) //add it
Is there a better way to handle this maybe? Thanks!
edit
The source of your problem seams to be the is_same function not resolving correctly at compile time.
/edit
You can always have template functions that only work with the specified types.
For example:
template<>
BaseMapManager<AnimationResource> get_map<AnimationResource>()
{
return animationMap;
}
template<>
BaseMapManager<ImageResource> get_map<ImageResource>()
{
return imageMap;
}
template<>
BaseMapManager<FontResource> get_map<FontResource>()
{
return fontMap;
}
The following is cute little template that I use often. Simply tells me if the given element is a member of a collection (which itself must be compatible with the find_if template):
// returns true if a given collection contains the given element
// NOTE: This is NOT optimized for associative containers!
template <typename ELEMENT, typename COLLECTION, typename PREDICATE>
bool contains(const COLLECTION & collection, ELEMENT element, PREDICATE predicate)
{
return collection.end() != std::find_if(collection.begin(), collection.end(), boost::bind(predicate, element, _1));
}
I'm finding that VC2012 balks if I try to use a lambda as the predicate:
if (!contains(specs, str, [] (CString pathname, CString pattern) { return AsBool(PathMatchSpec(pathname, pattern)); }))
continue;
VS2012SP1 spits out the following for the above context:
1>c:\users\steve\projects\cimex cad-cam\15.0\3rd party\boost\boost\bind\bind.hpp(69): error C2039: 'result_type' : is not a member of 'CMacroInterpreter::GetDirectoryOf::<lambda_60eac39ee69a5bdc77e08d06d79ae4c4>'
1> c:\users\steve\projects\cimex cad-cam\15.0\cimex application\cimcad\macro directory.cpp(166) : see declaration of 'CMacroInterpreter::GetDirectoryOf::<lambda_60eac39ee69a5bdc77e08d06d79ae4c4>'
1> c:\users\steve\projects\cimex cad-cam\15.0\3rd party\boost\boost\bind\bind_template.hpp(15) : see reference to class template instantiation 'boost::_bi::result_traits<R,F>' being compiled
1> with
1> [
1> R=boost::_bi::unspecified,
1> F=CMacroInterpreter::GetDirectoryOf::<lambda_60eac39ee69a5bdc77e08d06d79ae4c4>
1> ]
1> c:\users\steve\projects\cimex cad-cam\15.0\mfc toolbox\miscellaneous.h(360) : see reference to class template instantiation 'boost::_bi::bind_t<R,F,L>' being compiled
1> with
1> [
1> R=boost::_bi::unspecified,
1> F=CMacroInterpreter::GetDirectoryOf::<lambda_60eac39ee69a5bdc77e08d06d79ae4c4>,
1> L=boost::_bi::list2<boost::_bi::value<CString>,boost::arg<1>>
1> ]
1> c:\users\steve\projects\cimex cad-cam\15.0\cimex application\cimcad\macro directory.cpp(166) : see reference to function template instantiation 'bool contains<CString,substring_container_adapter,CMacroInterpreter::GetDirectoryOf::<lambda_60eac39ee69a5bdc77e08d06d79ae4c4>>(const COLLECTION &,ELEMENT,PREDICATE)' being compiled
1> with
1> [
1> COLLECTION=substring_container_adapter,
1> ELEMENT=CString,
1> PREDICATE=CMacroInterpreter::GetDirectoryOf::<lambda_60eac39ee69a5bdc77e08d06d79ae4c4>
1> ]
I'm unclear on how to coerce things to accept the predicate lambda. Seems that boost is unable to deduce the return type of the lambda. And I'm unclear on what I can do to fix that?
I could define a local std::binary_function derivative functor. Just seems like it would be better to fix contains<> to allow it to handle lambdas directly.
It seems to be an issue with boost::bind. Using std::bind instead, your code builds fine with lambdas in VS2012:
#include <functional>
#include <algorithm>
#include <vector>
template <typename ELEMENT, typename COLLECTION, typename PREDICATE>
bool contains(const COLLECTION & collection, ELEMENT element, PREDICATE predicate)
{
return collection.end() != std::find_if(collection.begin(), collection.end(), std::bind(predicate, element, std::placeholders::_1));
}
std::vector<int> a;
int main()
{
a.push_back(1);
a.push_back(2);
a.push_back(3);
a.push_back(42);
bool c = contains(a, 42, [](int a, int b) { return a == b; });
return 0;
}
The same code builds just fine with g++ as well.
You could always try using another lambda:
template <typename ELEMENT, typename COLLECTION, typename PREDICATE>
bool contains(const COLLECTION & collection, ELEMENT element, PREDICATE predicate)
{
typedef typename COLLECTION::value_type VALUE;
return collection.end() != std::find_if(collection.begin(), collection.end(),
[&]( VALUE const & e ){ return predicate( element, e ); });
}
I'm using Boost.PropertyTree for a project and I want to use user-defined types for Key and Data instead of the std::string that Boost uses in the ptree typedef.
However when I typedef basic_ptree myself I get the following compiler errors:
1> main.cpp
1>c:\boost_1_49_0\boost\property_tree\ptree.hpp(82): error C2027: use of undefined type 'boost::property_tree::path_of<Key>'
1> with
1> [
1> Key=int
1> ]
1> c:\users\mathias\documents\visual studio 2012\projects\testappern\testappern\main.cpp(10) : see reference to class template instantiation 'boost::property_tree::basic_ptree<Key,Data>' being compiled
1> with
1> [
1> Key=int,
1> Data=int
1> ]
1>c:\users\mathias\documents\visual studio 2012\projects\testappern\testappern\main.cpp(13): error C2664: 'boost::property_tree::basic_ptree<Key,Data>::add_child' : cannot convert parameter 1 from 'int' to 'const boost::type &'
1> with
1> [
1> Key=int,
1> Data=int
1> ]
1> Reason: cannot convert from 'int' to 'const boost::type'
1> The target type has no constructors
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
The following snippet shows and example how I typedef basic_tree and get the compiler errors:
#include <iostream>
#include <boost\property_tree\ptree.hpp>
using namespace boost::property_tree;
typedef basic_ptree<int, int> IntTree;
int main(int argc, char* argv[])
{
IntTree tree;
IntTree child;
int index = 42;
tree.add_child(index, child);
return 0;
}
So my question is, how do I typedef it correctly?
If it's any interest I'm running MSVC 2012.
Thanks in advance!
According to the contents of boost/property_tree/ptree_fwd.hpp, if you want to use a custom type as a key, you should follow this:
/// If you want to use a custom key type, specialize this struct for it
/// and give it a 'type' typedef that specifies your path type. The path
/// type must conform to the Path concept described in the documentation.
/// This is already specialized for std::basic_string.
So you can not simply use int. Refer to the documentation for more information, as the code says.
Here is an example of basic_ptree <int, int>
//path class must conform Path concept
template<> class boost::property_tree::path_of < int >
{
public:
typedef int key_type;
typedef boost::property_tree::path_of < int > type;
boost::property_tree::path_of<int>(vector<int>& vals)
{
std::transform(vals.begin(), vals.end(), back_inserter(_impl),
[&](int v) -> int{ return v; });
}
key_type reduce()
{
key_type res = *_impl.begin();
_impl.pop_front();
return res;
}
bool empty() const
{
return _impl.empty();
}
bool single() const
{
return _impl.size() == 1;
}
std::string dump() const
{
std::string res;
std::for_each(_impl.begin(),
_impl.end(), [&res](key_type k) -> void
{
res.append(".");
res.append(boost::lexical_cast<std::string>(k));
});
return res;
}
private:
deque<key_type> _impl;
};
//usage:
typedef boost::property_tree::basic_ptree < int, int> custom_int_tree_t
//or
typedef boost::property_tree::basic_ptree < int, void*> custom_int_tree2_t
Wordy title, yes, but I was unsure how else to say it. Suppose I have a container class which has two template parameters, the first of which is a type, the second of which is the size of the local storage for the container.
Now we have multiple containers with a different container storage size. Essentially, the container functions (all the public ones, anyway) only really care about T; N is only used to allocate local storage (an allocator is used if N is not enough).
I have put together a simple example implementation that showcases the problem I am having.
#include <iostream>
template <typename T, size_t N = 10>
class TestArray
{
public:
T Local[N];
class Iterator
{
public:
T* Array;
int Index;
Iterator() : Array(NULL), Index(-1) { }
Iterator(T* _array, int _index) : Array(_array), Index(_index) { }
bool operator == (const Iterator& _other) const
{
return _other.Index == Index && _other.Array == Array;
}
void Next() { ++Index; }
void Prev() { --Index; }
T& Get() { return Array[Index]; }
};
T& operator [] (const int _index) { return Local[_index]; }
Iterator Begin() { return Iterator(Local, 0); }
Iterator End() { return Iterator(Local, N); }
template <size_t _N>
void Copy(const TestArray<T, _N> &_other, int _index, int _count)
{
int i;
for (i = 0; i < _count; i++)
Local[_index + i] = _other[i];
}
};
This is really a two part question. I will concern this question only with the first part, and ask another regarding the second. I tried using it as follows:
int main() {
TestArray<int> testArray1;
TestArray<int, 25> testArray2;
TestArray<int>::Iterator itr1;
TestArray<int, 25>::Iterator itr2;
itr1 = testArray1.Begin();
for (itr1 = testArray1.Begin(); itr1 != testArray1.End(); itr1.Next())
{
itr1.Get() = itr1.Index;
}
testArray2.Copy(testArray1, 0, 10);
for (itr2 = testArray2.Begin(); itr2 != testArray2.End(); itr2.Next())
{
std::cout << itr2.Get() << std::endl;
}
return 0;
}
Here is an IDEONE link: http://ideone.com/1XKwD
When compiled with gcc-4.3.4, I get the following.
prog.cpp: In member function ‘void TestArray<T, N>::Copy(const TestArray<T, _N>&, int, int) [with unsigned int _N = 10u, T = int, unsigned int N = 25u]’:
prog.cpp:82: instantiated from here
prog.cpp:63: error: passing ‘const TestArray<int, 10u>’ as ‘this’ argument of ‘T& TestArray<T, N>::operator[](int) [with T = int, unsigned int N = 10u]’ discards qualifiers
When compiled with VS2010, I get the following.
1>------ Build started: Project: testunholytemplatemess, Configuration: Debug Win32 ------
1> main.cpp
1>c:\users\james\documents\testproj\testunholytemplatemess\testunholytemplatemess\main.cpp(63): error C2678: binary '[' : no operator found which takes a left-hand operand of type 'const TestArray<T>' (or there is no acceptable conversion)
1> with
1> [
1> T=int
1> ]
1> c:\users\james\documents\testproj\testunholytemplatemess\testunholytemplatemess\main.cpp(44): could be 'int &TestArray<T>::operator [](const int)'
1> with
1> [
1> T=int
1> ]
1> while trying to match the argument list '(const TestArray<T>, int)'
1> with
1> [
1> T=int
1> ]
1> c:\users\james\documents\testproj\testunholytemplatemess\testunholytemplatemess\main.cpp(82) : see reference to function template instantiation 'void TestArray<T,N>::Copy<10>(const TestArray<T> &,int,int)' being compiled
1> with
1> [
1> T=int,
1> N=25
1> ]
Maybe I'm being thick, but I'm failing to interpret what either of these is actually trying to tell me (still somewhat new to templates). I also fail to understand why the operator [] method should really care about N, or the fact that I'm calling operator [] on a container with a different N value. If you change _other[i] to _other.Local[i], it works fine.
Does anyone have any suggestions?
You have to overload two versions for the []-operator, a const one and a non-const one:
T & operator [] (size_t _index) { return Local[_index]; }
const T & operator [] (size_t _index) const { return Local[_index]; }
Your constant Copy function is only allowed to use the second, constant version!