#include <cinttypes>
#include <type_traits>
template<typename Id, typename Value>
class sparse_set {
static_assert(std::is_integral_v<Id>, ""); (1)
static_assert(std::is_unsigned_v<Id>, "");
Value& operator[](Id id);
void push_back(const Value& value);
// class implementation left out
};
class entity {
public:
explicit entity(std::uint32_t id) : _id(id) {}
~entity() = default;
std::uint32_t id() const {
return _id;
}
operator std::uint32_t() const { (2)
return _id;
}
private:
std::uint32_t _id;
}; // class entity
int main() {
const auto e = entity{2};
auto set = sparse_set<entity, int>{};
set.push_back(0);
set.push_back(1);
set.push_back(2);
set.push_back(3);
auto i = set[e]; (3)
return 0;
}
I am trying to use a class with a conversion operator to std::uint32_t (2) as an index into a container class (3).
Accessing an element with an instance of that class works and i get the right element.
But testing the class with a static_assert and std::is_unsigned_v and std::is_integral_v results in an assertion failure.
I need assertions to make sure Id can be used as an index.
When I static_assert with std::uint32_t everything works so I would expect the conversion operator to work aswell.
entity certainly is not an integral type. It can be converted to a type that can be used as index and thats what you require:
#include <type_traits>
template<typename Id, typename Value>
class sparse_set {
static_assert(std::is_convertible_v<Id,size_t>, "");
// class implementation left out
};
std::is_unsigned and std::is_integral only works for primitive types, it doesn't work for classes, even if they are implicitly convertible to a type they support. You can solve this by two ways:
Create your own trait:
#include <type_traits>
// ...
using uint16 = std::uint16_t;
using uint32 = std::uint32_t;
class entity { /* ... */ };
template <typename T>
struct is_valid_index : std::is_unsigned<T> {};
template <>
struct is_valid_index<entity> : std::true_type {};
template <typename T>
constexpr auto is_valid_index_v = is_valid_index<T>::value;
template<typename Id, typename Value>
class sparse_set {
static_assert(is_valid_index_v<Id>, "");
// ...
};
// ...
Remove std::is_unsigned completely and use std::is_convertible instead:
#include <type_traits>
// ...
using uint16 = std::uint16_t;
using uint32 = std::uint32_t;
class entity { /* ... */ };
template<typename Id, typename Value>
class sparse_set {
static_assert(std::is_convertible_v<Id, uint32>, "");
// ...
};
// ...
I am trying to create a filesystem interface so that my micro controller can interface with an SD card (and I decided to implement all of the File System stuff from the ground up). The problem is I don't know what file system will be on the card....It could be FAT16, FAT32, NFTS, ext3, ect.
So I created a the following abstract classes: FileSystem File and Directory. Now that is all fine and dandy but I am on a micro controller so I want to avoid using the new operator.
This leads to my creation of the UnionBase class (not a very helpful name). Basically this class holds a union of all of the different derived classes and allows you to convert between them:
struct BaseFile_t{
};
struct DerivedA : BaseFile_t{
};
struct DerivedB : BaseFile_t{
};
UnionBase<BaseFile_t,DerivedA,DerivedB> var; //Can now pass references
//of this into File system function
//so that they can modify the right
//Derived type (which can then be
//used as if it is the base type)
Now in order to pass this in I have a struct called FileSystemUnion or FSU for short. This basically just defines all of the necessary BaseUnion types.
The real problem is that it seems that it might end up being a type if recursive typedef (which I know is not allowed). Here is a shortened version of my code:
#include <stdio.h>
#include <iostream>
#include <string>
#include <conio.h>
#include <stdlib.h>
#include <fstream>
#include "prototypeInd/templates/UnionBase.h"
using namespace prototypeInd::templates;
template<class arg,class conv>
struct File{
};
template<class arg,class conv>
struct Directory : public File<arg,conv>{
};
template<class arg,class conv>
struct FS{
typedef Directory<arg,conv> Directory;
typedef File<arg,conv> File;
};
template<class arg,class conv>
struct DFile : public virtual File<arg,conv>{
};
template<class arg,class conv>
struct DDirectory : public virtual Directory<arg,conv>, public virtual DFile<arg,conv>{
void foo(typename conv::Directory::UnionType& d){
}
};
template<class arg,class conv>
struct DFS : public virtual FS<arg,conv>{
typedef DFile<arg,conv> File;
typedef DDirectory<arg,conv> Directory;
};
template<class arg,template<class,class> class fsa,template<class,class> class fsb>
struct FSU{
typedef UnionBase<FS<arg,FSU>,fsa<arg,FSU>,fsb<arg,FSU> > FS;
typedef UnionBase<typename ::FS<arg,FSU>::Directory,typename fsa<arg,FSU>::Directory,typename fsb<arg,FSU>::Directory> Directory;
typedef UnionBase<typename ::FS<arg,FSU>::File,typename fsa<arg,FSU>::File,typename fsb<arg,FSU>::File> File;
};
typedef FSU<int,DFS,DFS> thing;
DDirectory<int,thing> d;
int main(int d,char** thing){
}
The error I get is:
invalid use of incomplete type 'struct DDirectory<int, FSU<int, DFS, DFS> >'
Here is UnionBase.h (its huge but don't worry all of this is working):
#ifndef prototypeInd_templates_UnionBase_h
#define prototypeInd_templates_UnionBase_h
#include <type_traits>
template<class Type, uint64_t time,class First,class... Array>
class IndexOf_{
static const bool isSame = std::is_same<First,Type>::value;
public:
static const uint64_t value = isSame ? time : IndexOf_<Type,time+1,Array...>::value;
};
template<class Type, uint64_t time, class First>
class IndexOf_<Type,time,First>{
public:
//static_assert(std::is_same<First,Type>::value,"Not contained in list");
static const uint64_t value = time;
};
template<class Type,class... Array>
using IndexOf = IndexOf_<Type,0,Array...>;
template<class Target, class First, class... Rest>
class ContainsType{
public:
static const bool value = std::is_same<Target, First>::value ? true : ContainsType<Target,Rest...>::value;
};
template<class Target, class First>
class ContainsType<Target,First>{
public:
static const bool value = std::is_same<Target, First>::value;
};
//Best is the highes so far while rest is the rest of the list
template <class Best,class First, class... Rest>
class GetMaxSize{
//typedef typename GetFirstType<Rest...>::value First;
static const bool FirstBigger = sizeof(First) > sizeof(Best);
public:
typedef typename std::conditional<FirstBigger,typename GetMaxSize<First,Rest...>::value,typename GetMaxSize<Best,Rest...>::value >::type value;
};
template<class Best, class First>
class GetMaxSize<Best,First>{
static const bool FirstBigger = sizeof(First) > sizeof(Best);
public:
typedef typename std::conditional<FirstBigger,First,Best >::type value;
};
template<class From,uint16_t index,class UT,class First,class... Array>
struct cast{
static void apply(From** t,UT* f){
if (index == f->GetActive()){
*t = &((First)(*f));
}
else{
cast<From,index+1,UT,Array...>::apply(t,f);
}
}
};
template<class From,uint16_t index,class UT,class First>
struct cast<From,index,UT,First>{
static void apply(From** t,UT* f){
if (index == f->GetActive()){
*t = &((First)(*f));
}
}
};
template<class... Values>
class UnionType{
typedef typename GetMaxSize<Values...>::value internal_t;
internal_t data;
uint16_t active;
public:
template<class CastFrom, class Dummy = typename std::enable_if<ContainsType<CastFrom,Values...>::value, int>::type >
UnionType(CastFrom&& d) : data(reinterpret_cast<internal_t&>(d)),active(IndexOf<CastFrom,Values...>::value){
}
template<class CastTo, class Condition = typename std::enable_if<ContainsType<CastTo,Values...>::value,int>::type >
operator CastTo const&() const{
return reinterpret_cast<const CastTo&>(data);
}
uint16_t GetActive() const{
return active;
}
//This one actually uses casting of the active data type
template<class CastTo, class Condition = typename std::enable_if<!ContainsType<CastTo,Values...>::value,int>::type >
explicit operator CastTo*() const{
CastTo temp;
CastTo* ret = &temp;
cast<CastTo,0,UnionType,Values...>::apply(&ret,this);
return ret;
}
};
namespace prototypeInd{namespace templates{
template<class Base, class Thing>
struct IsPublicBase{
static const bool value = std::is_base_of<Base,Thing>::value && std::is_convertible<Thing*,Base*>::value;
};
template<class Base, class First, class... Rest>
struct AllInheritFrom{
static const bool value = IsPublicBase<Base,First>::value ? AllInheritFrom<Base,Rest...>::value : false;
};
template<class Base, class First>
struct AllInheritFrom<Base,First>{
static const bool value = IsPublicBase<Base,First>::value;
};
template<template<class> class Function,class First,class... Args>
struct AllFullfill{
static const bool value = Function<First>::value ? AllFullfill<Function,Args...>::value : false;
};
template<template<class> class Function,class First>
struct AllFullfill<Function,First>{
static const bool value = Function<First>::value;
};
template<class Base, class... Rest>
class UnionBase{
static_assert(AllInheritFrom<Base,Rest...>::value, "All of the elements of UnionBase must have Base as a public base");
public:
typedef UnionType<Rest...> UnionType;
private:
UnionType internal;
public:
UnionBase() : internal(typename GetFirstType<Rest...>::value()){};
UnionBase(Base&& value) : internal(value){
}
operator UnionType&(){
return internal;
}
Base* operator ->() const{
//return 0;
return &((Base&)internal);
}
};
//template<class Base, class... Rest>
//using UnionBase = UnionBase_<Base,Rest...>*;
}}
#endif
So the real question is: what should I do to make this work? I am open to restructuring a little bit, but after hours of trying everything I can think of I am almost ready to scrap the whole thing and start again.
The problem is that in certain places of code your classes are really incomplete.
According to [class.mem]/1:
A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-specifier.
Within the class member-specification, the class is regarded as complete within function bodies,
default arguments, using-declarations introducing inheriting constructors (12.9), exception-specifications, and
brace-or-equal-initializers for non-static data members (including such things in nested classes). Otherwise
it is regarded as incomplete within its own class member-specification.
When applied to your code, this means in particular that the class is incomplete within function parameter lists. Now let's look at the definition of DDirectory::foo():
template<class arg,class conv>
struct DDirectory : public virtual Directory<arg,conv>, public virtual DFile<arg,conv>{
void foo(typename conv::Directory::UnionType& d){
}
};
In the instantiation DDirectory<int,thing> conv is FSU<int,DFS,DFS>, so instantiation of it involves instantiation of UnionBases inside, and eventially to this:
static_assert(AllInheritFrom<Base,Rest...>::value, "All of the elements of UnionBase must have Base as a public base");
where one of classes is DDirectory<int,thing>. Remember, all this happens in the deducing the type of the parameter of foo(), so DDirectory<int,thing> is incomplete, and that's what the compiler is saying.
You could try to move that static_assert for example to the constructor of UnionBase, but it doesn't solve other error which I think is impossible to fix, and the reason is the same:
error: invalid application of 'sizeof' to an incomplete type 'DDirectory<int, FSU<int, DFS, DFS> >'
static const bool FirstBigger = sizeof(First) > sizeof(Best);
^~~~~~~~~~~~~
Here is a minimized example reproducing the problem:
#include <type_traits>
template <typename T1, typename T2>
struct BiggerType {
using type = typename std::conditional<(sizeof(T1) > sizeof(T2)), T1, T2>::type;
};
template<typename T>
struct S {
using B = BiggerType<S, int>;
// This causes the instantiation of BiggerType,
// leading to calculation of sizeof(S) which is incomplete
void foo(const typename B::type& bt) {
}
};
int main() {
S<int> s;
}
Or in very compressed form,
template<typename T>
struct S {
// Same problem here
void foo(typename std::conditional<(sizeof(S) > sizeof(int)), S, int>::type&) {
}
};
I have some conceptual problem in a class hierarchy, where the Base class depends on a fixed scalar type T, but the derived CRTP'ed classes use return value type deduction.
For example, consider the following class hierarchy:
template<typename ... Args> struct VectorBase;
template<typename T>
struct VectorBase<T>
{
virtual T eval(int) const = 0;
auto operator[](int i) {return this->eval(i);}
};
template<typename T, typename Derived>
struct VectorBase<T, Derived> : public VectorBase<T>
{
virtual T eval(int i) const override final { return this->operator[](i); }
auto operator[](int i) const
{
return static_cast<Derived const&>(*this).operator[](i);
}
};
template<typename T>
struct Vector : public VectorBase<T, Vector<T> >
{
//just for code shortness,
//in reality there is a container which returns the corresponding elements
auto operator[](int i) const { return T{}; }
};
template<typename VectorType>
struct SomeTransformation : public VectorBase< /* ... what to write here generically? */ double, SomeTransformation<VectorType> >
{
VectorType const& v;
SomeTransformation(VectorType const& _v) : v(_v) {}
auto operator[](int i) const
{
//do something with vector v and return i-th element, e.g.
return v[i]*0.1;
}
};
DEMO
Now, given a specific vector with value type int, say, one can apply SomeTransformation and get a vector of value type double. Moreover, I can be sure that SomeTransformation derives from VectorBase<double>, so that, for example, I can't falsely assign it to a VectorBase<int>-pointer:
int main()
{
Vector<int> v;
std::cout<<typeid(decltype(v[0])).name()<<std::endl; //prints "i" for int
auto u = SomeTransformation<decltype(v)>(v);
std::cout<<typeid(decltype(u[0])).name()<<std::endl; //prints "d" for double
//works
std::unique_ptr<VectorBase<double> > ud = std::make_unique<SomeTransformation<decltype(v)> >(v);
//gives a compile-time error, which is good
//std::unique_ptr<VectorBase<int> > ui = std::make_unique<SomeTransformation<decltype(v)> >(v);
}
Now for the problem: in the scalar type argument of SomeTransformation, where I wrote /* ... what to write here generically? */, I really would want to write something like
template<typename VectorType>
struct SomeTransformation :
public VectorBase<decltype(std::declval<SomeTransformation<VectorType> >().operator[](0)), SomeTransformation<VectorType> >
{
//...
};
in order to deduce the value type of the transformation automatically and propagate this type down to the base class. However, this doesn't seem to work, which I think is because the base classes are instantiated before the derived class ... so the class of which I want to deduce the type doesn't exists yet.
Is there any way to obtain this behaviour without breaking the inheritance hierarchy?
I figured out a possible alternative by myself and want to bring it up for discussion.
One could for instance add a type parameter T also to the derived class and then use a dummy type in order to instantiate this class once. With this, it is possible to deduce the return type of the so-created class, which is used in a next step to instantiate the class to be really used.
Example:
namespace detail
{
template<typename T, typename VectorType>
struct SomeTransformation :
public VectorBase<T, SomeTransformation<T, VectorType> >
{
//the same as above
};
}
struct DummyType
{
//make any type convertible to DummyType
template<typename T> DummyType(T const&) {}
};
template<typename VectorType>
using SomeTransformationValueType =
decltype(std::declval<detail::SomeTransformation<DummyType, VectorType> >().operator[](0));
template<typename VectorType>
using SomeTransformation =
typename detail::SomeTransformation<SomeTransformationValueType<VectorType>, VectorType>;
DEMO
I've already found a few threads to the topic of std::enable_if, but unfortunately I am not able to apply the examples to my code.
template<class From, class To, class Value>
struct convert
{
static Value apply(Value value)
{
return value;
}
};
I want this to be active only when From and To are the same, so I tried to use
std::enable_if<std::is_same<From,To>::value>::Value
But that doesn't work. How would I do this?
I also have these two specializations, to give you a better picture of my problem:
template<class From, class Value>
struct convert<From, kilometer, Value>
{
static Value apply(Value value)
{
doSomething;
}
};
template<class To, class Value>
struct convertImpl <kilometer, To, Value>
{
static Value apply(Value value)
{
doSomethingElse;
}
};
This is where my abguity problems come from. Right now I'm static_asserting the case that From and To are the same thus making the code to compile. But I would like to just return the value when those two are of the same type.
I don't think you want SFINAE for this, from your description I think you just want a specialization:
template<class From, class To, class Value>
struct convert
{
static Value apply(Value value)
{
Value somethingElse = ...;
return somethingElse;
}
};
template<class From, class Value>
struct convert<From,From,Value>
{
static Value apply(Value value)
{
return value; // SAME
}
};
I admit I honestly don't see the sense in this, as Value is an independent type from both From and To, but you probably know something about it which I don't. It would seem this is your desire if you want the full struct specialized. See it live.
Best of luck
template<class From, class To, class Value>
struct convert
{
template <typename F = From, typename T = To>
static auto apply(Value value) -> typename std::enable_if<std::is_same<F,T>::value, Value>::type
{
static_assert(std::is_same<F, From>::value && std::is_same<T, To>::value, "");
// no conversion
return value;
}
template <typename F = From, typename T = To>
static auto apply(Value value) -> typename std::enable_if<!std::is_same<F,T>::value, Value>::type
{
static_assert(std::is_same<F, From>::value && std::is_same<T, To>::value, "");
// do conversion
return value;
}
};
DEMO
Alternatively this can be implemented using a tag-based dispatching:
template<class From, class To, class Value>
struct convert
{
static Value apply(Value value)
{
using tag = std::integral_constant<bool, std::is_same<From, To>::value>;
return _apply(value, tag{});
}
private:
static Value _apply(Value value, std::true_type)
{
// no conversion
return value;
}
static Value _apply(Value value, std::false_type)
{
// do conversion
return value;
}
};
DEMO 2
I am very interested in the possibilities of template classes. Now, I am wondering how I can achieve following:
Const<5>::getValue();
At the moment I can do this:
Const<int, 5>::getValue());
And that's the implementation of the class:
template <typename T, T value>
class Const {
public:
typedef T Type;
static T getValue() {
return value;
}
};
I know this is just a very silly example, but once I can do that I could simplify following line:
Getter<int, TestClass, &TestClass::get> getter;
to just:
Getter<&TestClass::get> getter;
That would be TestClass :
class TestClass {
private:
int _value;
public:
int get() {
return _value;
}
};
Thanks for your help!
[EDIT-1]
In regards to J.N. yes, C++11 would be fine.
In regards to Xeo, I tried to use #define AUTO_ARG(x) decltype(x), x but that doesn't work within TestClass.
[EDIT-2]
In regards to KennyTM, when I declare the Getter<...> g within TestClass it doesn’t work with Getter<AUTO_ARG(&TestClass::get)> it only works with Getter<int (TestClass::*)() const, &TestClass::get>.
Now I am wondering if this is just a bug in Visual Studio???
You could still use AUTO_ARG(x) as given by #Xeo's link. If you need to get the return type or the class type, just use pattern matching (i.e. template specialization):
template <typename T, T mem_fun_ptr>
struct Getter;
template <typename R, typename C, typename... A, R (C::*mem_fun_ptr)(A...) const>
struct Getter<R (C::*)(A...) const, mem_fun_ptr>
{
typedef R return_type;
typedef C class_type;
};
#define AUTO_ARG(x) decltype(x),(x)
class TestClass {
private:
int _value;
public:
int get() const {
return _value;
}
};
Getter<AUTO_ARG(&TestClass::get)> g;