I want the class member variable only_if_int to be defined only if the class is instantiated with the template type int. I have a working solution, but it is too verbose.
#include <iostream>
#include <type_traits>
template<typename T, typename Enable = void>
class MyClass;
template<typename T>
class MyClass<T, std::enable_if_t<std::is_same<T, int>::value>>{
public:
int common;
int only_if_int;
MyClass()
{
common = 0;
only_if_int = 0;
}
void alter_values()
{
common++;
only_if_int++;
}
};
template<typename T>
class MyClass<T, std::enable_if_t<!std::is_same<T, int>::value>>{
public:
int common;
MyClass()
{
common = 0;
}
void alter_values()
{
common++;
}
};
int main()
{
MyClass<int> int_class;
MyClass<float> float_class;
int_class.alter_values();
float_class.alter_values();
std::cout<<"\n int_class "<<int_class.common<<" "<<int_class.only_if_int;
std::cout<<"\n int_class "<<float_class.common<<" ";
return 0;
}
In the above code, the templated class MyClass is defined twice(too much code duplicate). For eg: alter_values function is written twice. Is there a less verbose way, maybe with the help of constexpr std::is_same<T, int> or a different C++ feature to do the same thing?
One approach would be to have a type that contains an int member only if it's instantiated with int, like this:
template<typename>
struct OnlyInt {};
template<>
struct OnlyInt<int> {
int only_if_int;
};
Then MyClass can just inherit from this type:
template<typename T>
class MyClass : public OnlyInt<T> {
public:
int common;
// ... contains only_if_int if T == int
};
Now all uses of only_if_int will need to be wrapped in an if constexpr, and you have to use this-> to indicate that the member is from a base class. So for example:
only_if_int = 0;
becomes:
if constexpr (std::is_same_v<T, int>)
this->only_if_int = 0;
etc.
Here's a demo.
In the following task I want to create a template which only accepts typedefs defined in the following class CDataFormat:
class CDataFormat{
public:
typedef unsigned short element_t;
typedef unsigned int accumulation_t;
typedef double division_t;
};
Now the following implemention works fine.
template<typename DF, int SIZE>
class CFilter{
private:
DF m_memberName[SIZE];
public:
void whatever(){
//CFilter<CDataFormat::division_t, 8> smth; // Just a small test
}
};
However it's not ensured that the template only accepts a member of CDataFormat.
How do I do it?
You might use static_assert to report misusage:
template <typename DF, int SIZE>
class CFilter{
static_assert(std::is_same<CDataFormat::element_t, DF>::value
|| std::is_same<CDataFormat::accumulation_t, DF>::value
|| std::is_same<CDataFormat::division_t, DF>::value, "Unexpected type");
private:
DF m_memberName[SIZE];
};
You can use a helper class and static_assert to meet your needs.
#include <type_traits>
class CDataFormat{
public:
typedef unsigned short element_t;
typedef unsigned int accumulation_t;
typedef double division_t;
};
template <typename T> struct is_valid_type
{
static const bool value = std::is_same<T, CDataFormat::element_t>::value ||
std::is_same<T, CDataFormat::accumulation_t>::value ||
std::is_same<T, CDataFormat::division_t>::value ;
};
template<typename DF, int SIZE>
class CFilter{
static_assert(is_valid_type<DF>::value, "Unsupported type");
private:
DF m_memberName[SIZE];
public:
void whatever(){
}
};
With that,
CFilter<CDataFormat::element_t, 10> f1;
will work without any problem but use of
CFilter<int, 20> f2;
will result in a compile time error.
I am following this question in order to select the right container, but I am encountering problems.
I have a selector class that must push back into a vector of pointers, but the right one depends on its dimension (1 for vectors, 2 for matrices):
class selector
{
struct formValues : std::vector<coolvector<double>*>, std::vector<coolmatrix<double>*> { };
formValues maps;
public:
selector() { };
template<unsigned int formdim, typename F>
void operator+=(const form<formdim, F> &f)
{
typedef typename form<formdim, F>::storage_type storage_type;
typedef typename std::vector<storage_type*> pointer_type;
// Push to the right vector
formValues<pointer_type> &m = maps;
m.push_back(f.storage.get());
}
};
The forms class have a dimension and a storage, again depending on the dimension, using shared pointers:
template <bool, class if_true, class if_false>
struct type_switch
{
typedef if_false type;
};
template <class if_true, class if_false>
struct type_switch<true, if_true, if_false>
{
typedef if_true type;
};
template <class T> class coolvector {};
template <class T> class coolmatrix {};
template<unsigned int formdim, typename F>
class form
{
public:
form() = delete;
form(const std::string &s) : type(s)
{
storage = std::make_shared<storage_type>();
}
std::string type;
typedef typename type_switch<formdim == 1, coolvector<double>, coolmatrix<double>>::type storage_type;
std::shared_ptr<storage_type> storage;
};
class oneform : public form<1, oneform>
{
public:
oneform() = delete;
oneform(const std::string &s) : form(s) { };
double operator()(unsigned int i) { return i * 2; };
};
class twoform : public form<2, twoform>
{
public:
twoform() = delete;
twoform(const std::string &s) : form(s) { };
double operator()(unsigned int i, unsigned int j) { return i * 2 + j * 20; };
};
The problem is that in the selector::operator+= I get this error:
main.cpp:77:19: error: expected unqualified-id
formValues<pointer_type> &m = maps;
^
Any hints are appreciated!
formValues is not a template, so you can't write formValues<pointer_type>.
You appear to mean
pointer_type& m = maps;
to get the appropriate base class subobject of maps.
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 this situation:
template<unsigned int N>
class Base
{
public:
Base(){}
int myint[N];
};
template<unsigned int M>
class BaseWrapper : Base<M>
{
public:
BaseWrapper(){}
};
template<typename T>
class User
{
public:
User(){}
//int myint[T::N]; //How to statically allocate using M or N from above?
};
int main(void)
{
User<BaseWrapper<10> > myuser;
// Do something with User::myint here.
}
I want to be able to use the non-type parameter of the template argument to User to statically allocate data in the User class. I know I can use template template parameters to create BaseWrapper<M> inside User but this is not my preferred approach. Any simple methods to do this?
Thanks!
Add static const unsigned int Size = N; to your class.
Example:
template<unsigned int N>
class Base
{
public:
Base(){}
int myint[N];
static const unsigned int Size = N;
};
Then N is accessible as T::Size in your User class.
Solution 1
Declare a const static member data as:
template<unsigned int M>
class BaseWrapper : Base<M>
{
public:
static const unsigned int size = M; //add this line!
BaseWrapper(){}
};
Then use this as T::size in User class:
template<typename T>
class User
{
public:
User(){}
int myint[T::size]; //you can do this!
};
Solution 2
Or if you cannot add size as member (for whatever reason), then you can use this approach as:
template<typename T> struct get;
template<unsigned int N>
struct get< BaseWrapper<N> > //partial specialization!
{
static const unsigned int size = N;
};
template<typename T>
class User
{
public:
User(){}
int myint[get<T>::size]; //get the size!
};
You can expose the template parameter as a static member variable of the class:
template<unsigned int M>
class BaseWrapper : Base<M>
{
public:
static const int counter = M;
BaseWrapper(){}
};
Then you can use this static member in your User class:
template<typename T>
class User
{
public:
User(){}
int myint[T::counter];
};
The simplest way, which already has been mentioned by the others, is to add a static member to Basewrapper which is initialized to N.
However if for some reason you cannot change User, there's also a way to get at N:
template<typename T> struct get_N;
template<unsigned int N> struct get_N<Basewrapper<N> > { unsigned int const value = N; };
Now in your User template you just can write get_N<T>::value.
One advantage of this is that you can adapt any type after the fact without touching its definition, so if you ever want to instantiate User on anything else than a Basewrapper, say on Newbasewrapper, you just add the line
template<unsigned int N> struct get_N<Newbasewrapper<N> > { unsigned int const value = N; };
or if Newbasewrapper takes some type as template argument and provides the value of N as static const member,
template<typename T> struct get_N<Basewrapper<T> > { unsigned int const value = Basewrapper<T>::N; };