I have following struct:
template <size_t INDEX_SIZE, size_t GENERATION_SIZE>
struct Handle
{
uint32_t index : INDEX_SIZE;
uint32_t generation : GENERATION_SIZE;
};
In code I declare a lot of type aliases like this:
using Object1Handle = Handle<12, 16>;
using Object2Handle = Handle<12, 16>;
...
I would like to have possibility to extract INDEX_SIZE and GENERATION_SIZE from alias. It can be macro, meta-template or function. For example:
constexpr size_t indexSize = ExtractIndexSize<Object1Handle>::IndexSize;
Is it possible?
Yes, that is possible. Using specialization:
template<class HandleInst>
struct ExtractIndexSize;
template<size_t index_size_, size_t generation_size_>
struct ExtractIndexSize<
Handle<index_size_, generation_size_>
> {
static constexpr size_t index_size = index_size_;
static constexpr size_t generation_size = generation_size_;
};
However, in this simple example (as also pointed out in the comments to your question) the static constexpr size_t could also be moved to Handle.
An alternative yielding "getter-like" syntax and fewer restrictions is
template<class HandleInst>
struct ExtractIndexSize;
template<size_t index_size_, size_t generation_size_>
struct ExtractIndexSize<
Handle<index_size_, generation_size_>
> {
static constexpr size_t index_size() { return index_size_; }
static constexpr size_t generation_size() { return generation_size_; }
};
Related
I have a template class(CrMultiIndex) that receive as template parameter a definition of boost multi index(GlobalHash).
I need :
To add statistics to my template class according to Index used.
So i need a way to resize the vector(m_StatsByIndex) at init with the number of existing indices.
I still want the user to search according to tag and not index number.
So i need a way to convert from tag to index number so i can update statistics in vector according to index in vector.
I have template class
template <typename KeysType, typename MultiIndexType>
class CrMultiIndex
{
std::vector<SrStatisticsByIndex> m_StatsByIndex;
public:
MultiIndexType *m_pMultiIndex=NULL;
CrMultiIndex()
{
m_pMultiIndex = new MultiIndexType(typename
MultiIndexType::ctor_args_list());
}
Here is the definition of boost multi index container:
typedef boost::multi_index::multi_index_container<
CrUsersKeys,
UsersKey_hash_indices/*,
bip::allocator<CrUsersKeys,bip::managed_shared_memory::segment_manager>*/
> GlobalHash;
with a search function according to Tag
template <typename TagType,typename SearchingKey>
typename MultiIndexType::template index<TagType>::type::iterator
GetIteratorBy(SearchingKey & key)
{
return m_pMultiIndex->template get<TagType>().find(key) ;
}
Code is at http://coliru.stacked-crooked.com/a/d97195a6e4bb7ad4
You'd need to query the embedded index type lists:
typedef typename MultiIndexType::index_type_list::size NumberOfIndexes;
template <typename Tag> constexpr static size_t IndexOfTag() {
namespace mpl = boost::mpl;
using tl = typename MultiIndexType::index_type_list;
using B = typename mpl::begin<tl>::type;
using helper = typename MultiIndexType::template index<Tag>;
static_assert(helper::index_found, "index not found");
auto N = mpl::distance<B, typename helper::iter>::value;
return N;
}
Or, using Boost Mpl all the way:
typedef typename MultiIndexType::index_type_list::size NumberOfIndexes;
template <typename Tag> constexpr static size_t IndexOfTag() {
namespace mpl = boost::mpl;
using tl = typename MultiIndexType::index_type_list;
using B = typename mpl::begin<tl>::type;
using E = typename mpl::end<tl>::type;
using It = typename mpl::find_if<tl, bmi::detail::has_tag<Tag> >::type;
static_assert(not std::is_same<E, It>(), "index not found");
auto N = mpl::distance<B, It>::value;
return N;
}
You can use it like so:
template <typename TagType, typename SearchingKey>
typename MultiIndexType::template index<TagType>::type::iterator
GetIteratorBy(SearchingKey &key) {
auto& idx = m_pMultiIndex.template get<TagType>();
auto& stats = GetStats<TagType>();
auto it = idx.find(key);
++(it == idx.end()? stats.searchedNotFound : stats.searchedSuccessfully);
return it;
}
DEMO
Note the code has been simplified:
Live On Coliru
#include <iostream>
#include <boost/multi_index/member.hpp> // for member
#include <boost/multi_index/hashed_index.hpp> // for hashed_unique
#include <boost/multi_index/ordered_index.hpp> // for ordered_non_unique
#include <boost/multi_index_container.hpp> // for multi_index_container
namespace bmi = boost::multi_index;
struct SrStatisticsByIndex {
int deleted;
int searchedSuccessfully;
int searchedNotFound;
};
template <typename MultiIndexType, typename ValueType = typename MultiIndexType::value_type>
class CrMultiIndex {
typedef typename MultiIndexType::index_type_list::size NumberOfIndexes;
template <typename Tag> constexpr static size_t IndexOfTag() {
using tl = typename MultiIndexType::index_type_list;
using B = typename boost::mpl::begin<tl>::type;
using helper = typename MultiIndexType::template index<Tag>;
static_assert(helper::index_found, "index not found");
return boost::mpl::distance<B, typename helper::iter>::value;
}
public:
MultiIndexType m_pMultiIndex;
template <typename Tag> SrStatisticsByIndex& GetStats()
{ return m_StatsByIndex.at(IndexOfTag<Tag>()); }
template <typename Tag> SrStatisticsByIndex const& GetStats() const
{ return m_StatsByIndex.at(IndexOfTag<Tag>()); }
// All the protected function are non locking function
template <typename TagType, typename SearchingKey>
typename MultiIndexType::template index<TagType>::type::iterator
GetIteratorBy(SearchingKey &key) {
auto& idx = m_pMultiIndex.template get<TagType>();
auto& stats = GetStats<TagType>();
auto it = idx.find(key);
++(it == idx.end()? stats.searchedNotFound : stats.searchedSuccessfully);
return it;
}
void Insert(ValueType const &key) {
std::cout << (m_pMultiIndex.insert(key).second? "success":"failed") << std::endl;
}
private:
std::vector<SrStatisticsByIndex> m_StatsByIndex { NumberOfIndexes() };
};
class CrUsersValue {
int val1;
int val2;
};
class CrUsersKeys {
public:
int IMSI;
int TIMESTAMP;
CrUsersValue val;
};
typedef boost::multi_index::multi_index_container<
CrUsersKeys,
bmi::indexed_by<
bmi::ordered_non_unique<bmi::tag<struct TIMESTAMP_tag>,
bmi::member<CrUsersKeys, int, &CrUsersKeys::TIMESTAMP> >,
bmi::hashed_unique<bmi::tag<struct IMSI_tag>,
bmi::member<CrUsersKeys, int, &CrUsersKeys::IMSI> /*, boost::hash<int>, std::equal_to<int>*/>
>
/*, bip::allocator<CrUsersKeys,bip::managed_shared_memory::segment_manager>*/
>
GlobalHash;
int main() {
CrMultiIndex<GlobalHash> multi;
CrUsersKeys key;
key.IMSI = 2;
multi.Insert(key);
int searchKey = 2;
auto it = multi.GetIteratorBy<IMSI_tag>(searchKey);
if (it != multi.m_pMultiIndex.get<IMSI_tag>().end())
std::cout << "found " << std::endl;
}
Prints
success
found
As a supplement to sehe's answer, this a rewrite of IndexOfTag that does not depend on undocumented Boost.MultiIndex features:
Live On Coliru
template<typename MultiIndexContainer,std::size_t N=0>
struct index_position:index_position<MultiIndexContainer,N+1>
{
using index_type=typename boost::multi_index::nth_index<MultiIndexContainer,N>::type;
using index_position<MultiIndexContainer,N+1>::case_of;
static constexpr std::size_t case_of(std::in_place_type_t<index_type>){return N;}
};
template<typename MultiIndexContainer>
struct index_position<
MultiIndexContainer,
boost::mpl::size<typename MultiIndexContainer::index_type_list>::value
>
{
static constexpr void case_of(...){}
};
template <typename MultiIndexContainer,typename Tag>
constexpr std::size_t IndexOfTag()
{
using index_type=typename boost::multi_index::index<MultiIndexContainer,Tag>::type;
return index_position<MultiIndexContainer>::case_of(std::in_place_type<index_type>);
}
Edit: In C++14:
Live On Coliru
template<typename MultiIndexContainer,std::size_t N=0>
struct index_position:index_position<MultiIndexContainer,N+1>
{
using index_type=typename boost::multi_index::nth_index<MultiIndexContainer,N>::type;
using index_position<MultiIndexContainer,N+1>::case_of;
static constexpr std::size_t case_of(index_type*){return N;}
};
template<typename MultiIndexContainer>
struct index_position<
MultiIndexContainer,
boost::mpl::size<typename MultiIndexContainer::index_type_list>::value
>
{
static constexpr void case_of(...){}
};
template <typename MultiIndexContainer,typename Tag>
constexpr std::size_t IndexOfTag()
{
using index_type=typename boost::multi_index::index<MultiIndexContainer,Tag>::type;
return index_position<MultiIndexContainer>::case_of((index_type*)(nullptr));
}
Given the following template in a header file, and a couple of specializations:
template<typename> class A {
static const int value;
};
template<> const int A<int>::value = 1;
template<> const int A<long>::value = 2;
and building with clang-5, it results in errors for each source unit that included the file, all complaining about multiple definitions for A<int>::value and A<long>::value.
At first, I thought that maybe the template specializations needed to be put in a specific translation unit, but on checking the spec, this apparently should be allowed, because the value is a constant integer.
Am I doing something else wrong?
EDIT: if I move the definition into a single translation unit, then I can no longer use the value of A<T>::value in the context of a const int (eg, where its value is being used to calculate the value of another const assignment) , so the value really needs to be in a header.
In c++11 you maybe can go that way:
template<typename> class B {
public:
static const int value = 1;
};
template<> class B<long> {
public:
static const int value = 2;
};
template<typename T> const int B<T>::value;
If you only want to specialize the value var, you can use CRTP for that.
From C++17 you can make your definition inline:
template<> inline const int A<int>::value = 1;
template<> inline const int A<long>::value = 2;
Also from c++17 you can remove the 'template const int B::value;' for constexpr:
template<typename> class C {
public:
static constexpr int value = 1;
};
template<> class C<long> {
public:
static constexpr int value = 2;
};
// no need anymore for: template<typename T> const int C<T>::value;
And another solution for c++11 can be to use a inline method instead of inline vars which are allowed from c++17:
template<typename T> class D {
public:
static constexpr int GetVal() { return 0; }
static const int value = GetVal();
};
template <> inline constexpr int D<int>::GetVal() { return 1; }
template <> inline constexpr int D<long>::GetVal() { return 2; }
template< typename T>
const int D<T>::value;
In addition to your last edit:
To use your values also in other dependent definitions it seems to be the most readable version if you use the inline constexpr methods.
Edit: "Special" version for clang, because as OP tells us, clang complains with "specialization happening after instantiation". I don't know if clang or gcc is wrong in that place...
template<typename T> class D {
public:
static constexpr int GetVal();
static const int value;
};
template <> inline constexpr int D<int>::GetVal() { return 1; }
template <> inline constexpr int D<long>::GetVal() { return 2; }
template <typename T> const int D<T>::value = D<T>::GetVal();
int main()
{
std::cout << D<int>::value << std::endl;
std::cout << D<long>::value << std::endl;
}
I told already that CRTP is possible if not the complete class should be redefined. I checked the code on clang and it compiles without any warning or error, because OP comments that he did not understand how to use it:
template<typename> class E_Impl {
public:
static const int value = 1;
};
template<> class E_Impl<long> {
public:
static const int value = 2;
};
template<typename T> const int E_Impl<T>::value;
template < typename T>
class E : public E_Impl<T>
{
// rest of class definition goes here and must not specialized
// and the values can be used here!
public:
void Check()
{
std::cout << this->value << std::endl;
}
};
int main()
{
E<long>().Check();
std::cout << E<long>::value << std::endl;
E<int>().Check();
std::cout << E<int>::value << std::endl;
}
I'm trying to make C-string size calculation at compile time, using code like this:
#include <stdio.h>
#include <stdint.h>
class StringRef
{
public:
template<int N>
constexpr StringRef(const char (&str)[N])
: m_ptr(str), m_size(uint32_t(N-1)) {}
constexpr const char *constData() const
{ return m_ptr; }
private:
const char *m_ptr;
uint32_t m_size;
};
struct S
{
StringRef str;
};
constexpr static const struct S list[] =
{
"str",
};
int main()
{
printf("%s\n", list[0].str.constData());
return 0;
}
In clang-3.7 everything is fine, but in GCC 4.9.3-5.3 I get:
error: could not convert '(const char*)"str"' from 'const char*' to
'StringRef'
It can be fixed by adding explicit braces:
constexpr static const struct S list[] =
{{
{ "str" },
}};
But code became ugly and, still, clang somehow understand it correctly.
How can I make gcc understand array initialization without explicit braces?
I am trying to create an stl container of a move-only type that uses its own allocator in VStudio 2012.
The trouble is: it seems as though I have to provide a construct function for the allocator which in turn needs access to a public copy constructor on the contained type.
I either get:
error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>'
or
error C2039: 'construct' : is not a member of 'MyAllocator'
The same code works in clang so I suspect the problem is due to Microsoft but can anyone suggest a possible work around?
This is my code for minimal reproduction
#include <memory>
#include <vector>
using namespace std;
template< typename T>
struct MyAllocator
{
typedef T value_type;
typedef value_type* pointer;
typedef value_type& reference;
typedef const value_type* const_pointer;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
template<class t_other>
struct rebind
{
typedef MyAllocator<t_other> other;
};
MyAllocator():m_id(0) {}
MyAllocator(int id):m_id(id){}
template <class T>
MyAllocator(const MyAllocator<T>& other)
:m_id(other.getId())
{
}
T* allocate(std::size_t n)
{
return reinterpret_cast<T*>(malloc(sizeof(T) * n));
}
void deallocate(T* p, std::size_t n)
{
free(p);
}
int getId() const{ return m_id;}
//Have to add these although should not be necessary
void construct(pointer mem, const_reference value)
{
std::_Construct(mem, value);
}
void destroy(pointer mem)
{
std::_Destroy(mem);
}
private:
int m_id;
};
template <class T1, class U>
bool operator==(const MyAllocator<T1>& lhs, const MyAllocator<U>& rhs)
{
return lhs.getId() == rhs.getId() ;
}
template <class T1, class U>
bool operator!=(const MyAllocator<T1>&, const MyAllocator<U>&)
{
return lhs.getId() != rhs.getId();
}
//define a move only type
typedef unique_ptr<uint32_t> MyIntPtr;
//define a container based on MyIntPtr and MyAllocator
typedef vector<MyIntPtr, MyAllocator<MyIntPtr> > MyVector;
int main(int argc, char* argv[])
{
MyAllocator<MyIntPtr> alloc1(1);
MyVector vec(alloc1);
uint32_t* rawPtr = new uint32_t;
*rawPtr = 18;
vec.emplace_back(rawPtr);
return 0;
}
The error you get is because you try to construct a std::unique_ptr from a constant reference to a std::unique_ptr of the same type - and there is no such constructor.
You can rework your construct method to take an an rvalue reference and then everything compiles nicely:
void construct(pointer mem, value_type&& value)
{
std::_Construct(mem, std::move(value));
}
Consider this:
struct TestStruct
{
uint16_t m_a : 8;
uint16_t m_b : 8;
};
template<typename T>
struct some_trait
{
constexpr static const TestStruct value = {0,0};
};
template<>
struct some_trait<int>
{
constexpr static const TestStruct value = {1,1};
};
template<class T>
class Obj
{
public:
Obj(TestStruct t = some_trait<T>::value) : m_t(t)
{
}
TestStruct m_t;
};
int main(int argc, const char * argv[])
{
// Linker error here -> Undefined symbol for some_trait<int>::value
Obj<int> o;
TestStruct t = some_trait<int>::value;
Obj<int> o1(t); // -> This works
}
The following produces a linker error, complaining that the some_trait is not defined. I have two questions:
Why is this happening? I'm guessing it has to do with either the constexpr specifier or the non-POD type of TestStruct ?
Is there a way to make it work, while still keeping the default value in the constructor?
Thanks!