c++ avoid vector<bool> instantiation - c++

I have some class template over std::vector:
template<typename T>
class MyClass{
public:
// public methods;
private:
std::vector<T> buffer_;
// private methods and members
};
This is simplified version of my class. Internal vector here used as a buffer for sorting, different IO operation, relying on its single memory piece implementation such as fstreams custom buffer and buffer size known on runtime only.
All is ok, but vector<bool> instantiation absolutely doesn't suitable for such purpose. I would like to have vector<char> or vector<uint8_t> instead of vector<bool> instantiations in my class. Also I cant use additional libraries like boost, standart library only.
Is there any workaround?

Create a helper class to determine the value type for the vector (this code uses C++11 but can easily be rewritten using only C++98):
template<typename T>
struct VectorValueType {
using type = T;
};
template<>
struct VectorValueType<bool> {
using type = char;
};
template<typename T>
using VectorValueType_t = typename VectorValueType<T>::type;
template<typename T>
class MyClass{
private:
std::vector<VectorValueType_t<T>> buffer_;
};

Use a wrapper subclass like so:
template<typename T>
struct sub_vector: public vector<T> {};
template<>
struct sub_vector<bool>: public vector<char> {};
And then just use that instead of vector.

Use template specialization for the T=bool type.
Then for all types except bool, vector is used.
template <typename T>
class MyClass
{
private:
std::vector<T> buffer_;
};
template <>
class MyClass<bool>
{
private:
std::vector<char> buffer_;
};
You need to specialize every member function that you will add, too.

Related

How to specialize a template-class with doubles?

I write a template class dependent on a given type and variadic types, like so:
template<typename ConstType,typename...Inputs>
class ConstantTensor;
Then I write another class, which is generally defined in this way (assume wrong_type whatever type you want, but which is different from the following specialization ):
template<typename T>
class X{
public:
using type=wrong_type;
}
And I also have a specialization of this kind:
template<typename ConstType,typename...Inputs>
class X< ConstantTensor< ConstType ,Inputs...>>
{
public:
using type=right_type;
}
My problem is that, if I define the type ConstantTensor<ConstType,double> and then I want to use X<ConstantTensor<ConstType,double>>::type, the general case is called and not the specialization. So I obtain wrong_type instead of right_type. I guess it has to deal with the double type...Could you explain me why and how can I solve this issue? Thank you in advance.
EDIT:
Here a snippet of code, I hope it works:
class Scalar
{};
template<typename ConstType,typename...Inputs>
class ConstantTensor
{
public:
constexpr ConstantTensor(const Inputs&...inputs)
{}
};
template<typename ConstType,typename...Inputs>
constexpr auto Constant(const Inputs&...inputs)
{return ConstantTensor<ConstType,Inputs...>(inputs...);}
template<typename T>
class X{
public:
using type=int;
};
template<typename ConstType,typename...Inputs>
class X<ConstantTensor<ConstType,Inputs...>>{
public:
using type=char;
};
int main()
{
constexpr auto delta=Constant<Scalar>(2.0);
using type= X<decltype(delta)>::type; // this is int not char
}
The problem is that
constexpr auto delta=Constant<Scalar>(2.0);
is a constexpr variable; so it's also const.
So decltype(delta) isn't ConstantTensor<Scalar> but is a ConstantTensor<Scalar> const.
You can verify adding const in partial specialization declaration
template<typename ConstType,typename...Inputs>
class X<ConstantTensor<ConstType,Inputs...> const>{ // <-- added const
public:
using type=char;
};
Now you get that type is char.
-- EDIT --
The OP asks
Is there a short/elegant way to deal with both cases, const and non const, without duplicating the code?
I don't know if it's elegant, but it seems to me short enough: you can use a sort of self-inheritance adding the following partial specialization.
template <typename T>
class X<T const> : public X<T>
{ };
So X<ConstantTensor<Scalar> const> inherit from X<ConstantTensor<Scalar>>.

How to inherit std::vector template in user-defined class template in C++11?

I am trying to inherit the std::vector class template into my membvec class template as public. And I want to use it as e.g. say membvec<float> mymemb(10) with the intention of creating my membvec variable mymemb containing 10 elements.
But I can't figure out how to write the templatised declaration of the public inheritance. What I am doing is the following, but all in vain.
template <typename T, template <typename T> class std::vector = std::vector<T>>
//error above: expected '>' before '::' token
class membvec: public std::vector<T>
{
const membvec<T> operator-() const; // sorry the previous version was a typo
//error above: wrong number of template arguments (1, should be 2)
...
};
I think you're looking for something like the below, but seriously don't do it. If you ever pass your class as its parent std::vector, there is no virtual interface to allow your class to provide any benefit whatsoever. And if you don't need to substitute for a std::vector then there's no need to inherit from it. Prefer free function algorithms or containing the std::vector as a member in your class instead.
#include <vector>
template <typename T>
class membvec: public std::vector<T>
{
// Don't need <T> in class scope, must return by value.
membvec operator+() const;
};
int main()
{
membvec<int> foo;
}
Perhaps you want something like this:
#include <vector>
template <typename T, template <typename T, class Allocator> class Vec = std::vector>
class membvec: public Vec<T, std::allocator<T>>
{
public:
// This is the signature in your question, but it's questionable.
const membvec<T, Vec> &operator+(int x) const
{
// You obviously want to change this.
return *this;
}
};
You can then use it regularly:
int main()
{
membvec<char> foo;
foo + 3;
}

Template template parameters - extension to std::array

I have a question about template template parameters:
Let's consider the following class:
template<typename T, template<class, class=std::allocator<T> > class UnderlyingContainerType = std::vector>
class MyContainer
{
public:
T Value1;
T Value2;
UnderlyingContainerType<T> Container;
MyContainer() {}
/* methods implementation goes here */
};
In this example, MyContainer is a container chat uses an underlying STL-compatible container to do whatever stuff.
Declaring the underlying container type as a template template parameters, instead of a regular template argument, allows handy usage of the class MyContainer, such as:
MyContainer<int> MCV; //implicitly using vector
MyContainer<int, std::list> MCL; //no need to write std::list<int> thanks to the
//template template parameters
Now, while this would work perfectly with most of the STL-container, such as std::vector, std::deque, std::list, and so forth, it would not work, for example, with std::array provided in c++11.
The reason is that std::array has a different signature of template parameters than vector. Specifically, they are:
std::vector<class T, class allocator = std::allocator<T> >
std::array<class T, int N>
MY question is if there is a way to generalize the class MyContainer, so that the underlying container can be std::array as well.
I thank you in advance.
The commonality between the interfaces of vector and array are limited to the element type. Your container should reflect that:
template<typename T, template<typename> class underlying_container>
struct container
{
underlying_container<T> storage;
};
Usage now requires a tiny trick:
template<typename T> using vec = vector<T>;
template<typename T> using arr2 = array<T, 2>;
Note that vec, unlike vector, has a fixed allocator and that arr2, unlike array, has a fixed size.
Usage is now simple:
container<int, vec> a;
container<double, arr2> b;
See the example in action.
Alternatively, if you prefer to match up the interface to that used by vector, just add a template alias for array that instantiates the size and adds an unused type parameter:
template<typename T, typename> using arr2 = array<T, 2>;
See it in action.
I don't know how to achieve exactly, what you want. But if you don't require the ability to write MyContainer<int> MCV; you could use
template<class UnderlyingContainerType, class T = typename UnderlyingContainerType::value_type>
class MyContainer
{
public:
T Value1;
T Value2;
UnderlyingContainerType Container;
MyContainer() {}
/* methods implementation goes here */
};
int main() {
MyContainer<std::vector<int>> MCV{};
MyContainer<std::array<int, 5>> MCA{};
}
Which is not more to type than MyContainer<int, std::vector> MCV;
Also you can of course still add an alias for your vector based version:
template<class T>
using MyContainerV = MyContainer < std::vector<T> > ;

c++ class template specialization, without having to reimplement everything

I have a templatized class like so :
template<typename T>
class A
{
protected:
std::vector<T> myVector;
public:
/*
constructors + a bunch of member functions here
*/
}
I would like to add just ONE member function that would work only for 1 given type of T. Is it possible to do that at all without having to specialize the class and reimplement all the other already existing methods?
Thanks
The simplest and cleanest solution is to use a static_assert() in the body of a method, rejecting other types than the selected one (in the below example only integers are accepted):
#include <type_traits>
#include <vector>
template <typename T>
class A
{
public:
void onlyForInts(T t)
{
static_assert(std::is_same<T, int>::value, "Works only with ints!");
}
protected:
std::vector<T> myVector;
};
int main()
{
A<int> i;
i.onlyForInts(1); // works !
A<float> f;
//f.onlyForInts(3.14f); // does not compile !
}
OK CASE DEMO
NOK CASE DEMO
This utilizes the fact that a compiler instantiates a member function of a class template only when one is actually used (not when the class template is instantiated itself). And with the above solution, when a compiler tries to do so, it fails due to the execution of a static_assert.
C++ Standard Reference:
§ 14.7.1 Implicit instantiation [temp.inst]
Unless a function template specialization has been explicitly instantiated or explicitly specialized, the function template specialization is implicitly instantiated when the specialization is referenced in a context that requires a function definition to exist. Unless a call is to a function template explicit specialization or to a member function of an explicitly specialized class template, a default argument for a function template or a member function of a class template is implicitly instantiated when the function is called in a context that requires the value of the default argument.
[ Example:
template<class T> struct Z {
void f();
void g();
};
void h() {
Z<int> a; // instantiation of class Z<int> required
Z<char>* p; // instantiation of class Z<char> not required
Z<double>* q; // instantiation of class Z<double> not required
a.f(); // instantiation of Z<int>::f() required
p->g(); // instantiation of class Z<char> required, and
// instantiation of Z<char>::g() required
}
Nothing in this example requires class Z<double>, Z<int>::g(), or Z<char>::f() to be implicitly
instantiated. — end example ]
Yes, it's possible in C++03 with CRTP (Curiously recurring template pattern):
#include <numeric>
#include <vector>
template<typename Derived, typename T>
struct Base
{
};
template<typename Derived>
struct Base<Derived, int>
{
int Sum() const
{
return std::accumulate(static_cast<Derived const*>(this)->myVector.begin(), static_cast<Derived const*>(this)->myVector.end(), int());
}
};
template<typename T>
class A : public Base<A<T>, T>
{
friend class Base<A<T>, T>;
protected:
std::vector<T> myVector;
public:
/*
constructors + a bunch of member functions here
*/
};
int main()
{
A<int> Foo;
Foo.Sum();
}
As an alternative solution, which works also in plain C++03 (as opposed to static_assert or enable_if solutions), you may add extra defaulted template argument which will let you have both
specialized and unspecialized version of class. Then you can inherit your specialized version from the unspecialized one.
Here is a sample snippet:
#include <vector>
template<typename T, bool unspecialized = false>
class A
{
protected:
std::vector<T> myVector;
public:
void setVec(const std::vector<T>& vec) { myVector = vec; }
/*
constructors + a bunch of member functions here
*/
};
template<>
class A<int, false> : public A<int, true>
{
public:
int onlyForInt() {
return 25;
}
};
int main() {
// your code goes here
std::vector<int> vec;
A<int> a;
a.setVec(vec);
a.onlyForInt();
return 0;
}
The drawbacks of this solution is the need to add constructor forwarders, if class
has non-trivial constructors.
The static_assert technique by #PiotrS. works nicely. But it's also nice to know that you can specialize a single member function without code duplication. Just give the generic onlyForInts() an empty no-op implementation, and specialize it out-of-class for int
#include <vector>
template <typename T>
class A
{
public:
void onlyForInts(T t)
{
// no-op
}
protected:
std::vector<T> myVector;
};
template<>
void A<int>::onlyForInts(int t)
{
// works
}
int main()
{
A<int> i;
i.onlyForInts(1); // works !
A<float> f;
f.onlyForInts(3.14f); // compiles, but does nothing !
}
Live Example.
This technique comes in handy if you want to have int specific behavior without completely disabling the generic behavior.
One approach not given yet in the answers is using the standard library std::enable_if to perform SFINAE on a base class that you inherit to the main class that defines appropriate member functions.
Example code:
template<typename T, class Enable = void>
class A_base;
template<typename T>
class A_base<T, typename std::enable_if<std::is_integral<T>::value>::type>{
public:
void only_for_ints(){/* integer-based function */}
};
template<typename T>
class A_base<T, typename std::enable_if<!std::is_integral<T>::value>::type>{
public:
// maybe specialize for non-int
};
template<typename T>
class A: public A_base<T>{
protected:
std::vector<T> my_vector;
};
This approach would be better than an empty function because you are being more strict about your API and better than a static_cast because it simply won't make it to the inside of the function (it won't exist) and will give you a nice error message at compile time (GCC shows "has no member named ‘only_for_ints’" on my machine).
The downside to this method would be compile time and code bloat, but I don't think it's too hefty.
(don't you dare say that C++11 requirement is a down-side, we're in 2014 god-damnit and the next standard has even be finalized already!)
Also, I noticed, you will probably have to define my_vector in the base class instead of the final because you probably want to handle that data within the member function.
A nice way to do that without duplicating a bunch of code is to create a base base class (good god) and inherit that class in the base class.
Example:
template<typename T>
class base_data{
protected:
std::vector<T> my_vector;
};
template<typename T>
class A_base<T, typename std::enable_if<std::is_integral<T>::value>::type>: public base_bata<T>{
public:
void only_for_ints(){/* phew, finally. fiddle around with my_vector! */}
};
// non-integer A-base
template<typename T>
class A: public A_base<T>{
protected:
// helper functions not available in base
};
That does leave a horrible looking multiple-inheritance scheme, but it is very workable and makes it easy to define members based on template parameters (for future proofing).
People often don't like multiple-inheritance or how complicated/messy SFINAE looks, but I couldn't live without it now that I know of it: the speed of static code with the polymorphism of dynamic code!
Not sure where I found this, but you can use = delete; as the function definition inside the class, thereby deleting the function for the general case, and then explicitly specialize outside the class:
template <typename T>
struct A
{
auto int_only(T) -> void = delete;
};
template <> auto A<int>::int_only(int) -> void {}
int main()
{
auto a_int = A<int>{};
auto a_dbl = A<double>{};
a_int.int_only(0);
// a_dbl.int_only(3.14); error: call to deleted member function
}
https://en.cppreference.com/w/cpp/language/function#Deleted_functions

template types in a container class

I writing an "Effect" class (for an opengl program) and I'm also attempting to write a container class for.
The Effect class is defined as follows:
template <typename T>
class Effect
{
private:
Vbo<T> m_Vbo;
};
Where T is a type that describes the vertex attributes.
In order to write a container class, I'd like to store these effects in an std::map:
class EffectMgr : public Singleton <EffectMgr>
{
private:
typedef std::map<std::string, Effect<T> & > EffectMap;
};
The error I get with the container class is that T is undefined. Can someone enlighten me?
I may have (by sheer chance and tinkering) have found the answer although I won't know until I've written the container class:
class EffectMgr : public Singleton <EffectMgr>,
{
private:
template <typename T>
typedef std::map<std::string, Effect<T> & > EffectMap;
};
T is scoped within the Effect definition. Outside of the scope T is undefined.
Perhaps you mean this?
template <typename T>
class EffectMgr : public Singleton <EffectMgr>
{
private:
typedef std::map<std::string, Effect<T> & > EffectMap;
};
// use: EffectMgr<type>::EffectMap
If you want only the typedef to be templated then do this:
class EffectMgr : public Singleton <EffectMgr>
{
private:
template <typename T>
using EffectMap = std::map<std::string, Effect<T> & >; // C++11 feature
};
// use: EffectMgr::EffectMap<type>
Since Effect is a template class, and you're not specializing it inside EffectMgr, it also needs to be a template:
template<typename T>
class EffectMgr : public Singleton <EffectMgr>
{
private:
typedef std::map<std::string, Effect<T> & > EffectMap;
};
As I understand, you want to store effects with a different T-ypes in a map.
If it is, the simplest way would be specify interface
class IEffect
{
public:
virtual ~IEffect() = 0;
}
IEffect::~IEffect()
{
}
and implement it in your template:
template <typename T>
class Effect: public IEffect
{
private:
Vbo<T> m_Vbo;
};
now, you can create std::map<std::string, IEffect* >
With additional effort, you can write a wrapper over IEffect to get rid of pointers.