Using template value inside nested class - c++

I have the following class definition:
template <int B>
class SparseBitvector
{
typedef typename std::vector<std::bitset<B>> BitsetVector;
public:
class iterator: public std::iterator<...>
{
public:
explicit iterator(..., BitsetVector::iterator* _chunksIt, ...) {...}
}
}
At compilation I get this error:
/project/powerset/src/powerset/sparse_bitvector.h:96:125: error: 'std::BitsetVector<std::bitset<(long unsigned int)B>, std::allocator<std::bitset<(long unsigned int)B> > >::iterator' is not a type
explicit iterator(SortedStaticSet<EHRule> *_offsets, std::vector<std::bitset<B>> *_chunks, SetElement* _offssetsIt, BitsetVector::iterator* _chunksIt, int _indInBitset)
Is it allowed to use template value inside a nested class?
If not, is there some other error I am making?

You need to use typename keyword for depended types. Here for example
typename BitsetVector::iterator* _chunksIt
//^^^^^^
Secondly, there is no typename needed for the template type alias
typedef std::vector<std::bitset<B>> BitsetVector;
// or better use
// using BitsetVector = std::vector<std::bitset<B>>;
The minimal example for the above have considered as follows:
#include <vector>
#include <iterator>
#include <bitset>
template <int B>
class SparseBitvector
{
typedef std::vector<std::bitset<B>> BitsetVector;
public:
class iterator : public std::iterator<std::input_iterator_tag, BitsetVector>
{
public:
explicit iterator(std::input_iterator_tag, BitsetVector, typename BitsetVector::iterator* _chunksIt)
{
}
};
};

Related

Google Test multi-templates - compiler error

I am studying the answer of How to test c++ template class with multiple template parameters using gtest? . But I cannot compile the code from the answer there. To test the code, I created a minimal (unfortunately not working) example.
EDIT: I update the code again (considering the comment from Marko Popovic):
#include <iostream>
#include "gtest/gtest.h"
template <typename A>
struct whoami { void tellme(){printf("I do not know!");} };
template <>
struct whoami<int> { void tellme(){printf("I am an integer!");} };
template <>
struct whoami<char> { void tellme(){printf("I am a character!");} };
template <>
struct whoami<bool> { void tellme(){printf("I am a boolean!");} };
template <class A, class B>
struct TypeDefs
{
typedef typename A firstType;
typedef typename B secondType;
};
template <class T>
class ATestExample : public testing::Test
{
protected:
ATestExample() {}
virtual ~ATestExample(){ }
};
typedef ::testing::Types <TypeDefs<char,char>, TypeDefs<int,int> > MyTypeList;
TYPED_TEST_CASE(ATestExample, MyTypeList);
TYPED_TEST(ATestExample, DefaultConstructor)
{
whoami<TypeParam::firstType> info;
info.tellme();
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
But it still gives the error:
debuging.cpp(..): error: a class or namespace qualified name is required
debuging.cpp(..): error: a class or namespace qualified name is required
debuging.cpp(..): error: nontype "gtest_TypeParam_::firstType" is not a type name
detected during:
implicit generation of "ATestExample_DefaultConstructor_Test<gtest_TypeParam_>::~ATestExample_DefaultConstructor_Test() [with gtest_TypeParam_=TypeDefs<char, char>]"
gtest/gtest.h(7209): here
instantiation of class "ATestExample_DefaultConstructor_Test<gtest_TypeParam_> [with gtest_TypeParam_=TypeDefs<char, char>]"
gtest/gtest.h(7209): here
implicit generation of "ATestExample_DefaultConstructor_Test<gtest_TypeParam_>::ATestExample_DefaultConstructor_Test() [with gtest_TypeParam_=TypeDefs<char, char>]"
gtest/gtest.h(7209): here
instantiation of class "ATestExample_DefaultConstructor_Test<gtest_TypeParam_> [with gtest_TypeParam_=TypeDefs<char, char>]"
Edit 2:
The solution is a position-permutation of "typename":
template <class A, class B>
struct TypeDefs
{
typedef A firstType;
typedef B secondType;
};
template <class T>
class ATestExample : public testing::Test
{
protected:
ATestExample() {}
virtual ~ATestExample(){ }
};
typedef ::testing::Types <TypeDefs<cpu,char>, TypeDefs<gpu,int> > MyTypeList;
TYPED_TEST_CASE(ATestExample, MyTypeList);
TYPED_TEST(ATestExample, DefaultConstructor)
{
whoami<typename TypeParam::firstType> info;
info.tellme();
}
You have two errors. The first one is that you have named your templated
struct Types, which creates a problem when it is used with ::testing::Types.
Lets assume you rename it to TypeDefs. Then, in the body of the test you have an error when declaring a typedef because you have not specified template parameters. You must do this:
typedef TypeDefs<char, int>::firstType someType;
Do not use typedef inside TYPED_TEST, use TypeParam directly:
whoami<TypeParam::firstType> info;
info.tellme();

How to use type traits to define a partially abstract template base class?

I'm working on the following idea:
There exists a generally abstract templated base class with mutiple template parameters. This class defines a contract guaranteeing the presence of certain methods i.e. a method getMax(). This method among others is generally purely virtual. Except there are special cases in which a sensible implementation can be given without the need to implement it manually every time in a derived class. So basically what I'm trying to achive is to (partially) implement the contracted methods already inside the abstract base class if the template arguments allow this.
I made a small example to illustrate the idea. (Note: The example is not perfect, for instance the implementation for std::string is very special and already implicitly forces TSize to be std::size_t)
#ifndef ABSTRACTBASE_H
#define ABSTRACTBASE_H
#include <type_traits>
#include <string>
#include <limits>
template <typename TSize, typename TVal1, typename TVal2>
class AbstractBase
{
public:
AbstractBase(){};
virtual ~AbstractBase() {};
virtual TSize getMax() const = 0; // <-- getMax should be generally
// purely virtual.
private:
TVal1 value1;
TVal2 value2;
};
//except when TVal1 is an arithmetic type in that case the following definition
//shall become active.
template <typename TSize,
typename TVal1,
typename TVal2,
typename = typename std::enable_if<std::is_arithmetic<TVal1>::value, TSize>::type>
TSize AbstractBase<TSize, TVal1, TVal2>::getMax() const
{
return std::numeric_limits<TVal1>::max();
}
//... or when TVal1 is a string where this defintion makes sense
template <typename TSize,
typename TVal1,
typename TVal2,
typename = typename std::enable_if<std::is_same<TVal1, std::string>::value, TSize>::type>
TSize AbstractBase<TSize, TVal1, TVal2>::getMax() const
{
return value1.max_size();
}
//... in all other cases the getMax() method shall stay purely virtual and an
//appropriate definition must be implemented inside a derived class
#endif //ABSTRACTBASE_H
#include "AbstractBase.h"
#include <string>
#include <iostream>
int main()
{
AbstractBase<int, int, int> arthBase();
AbstractBase<std::size_t, std::string, long> alphaBase();
std::cout << arthBase.getMax() << std::endl;
std::cout << alphaBase.getMax() << std::endl;
}
So I guess what is missing here is a method to actually also alter the declaration ov getMax() as virtual, though im not really sure if/how this is possible using type_traits.
Side note: I haven't worked with type traits very much yet. I know about the SFINAE principle behind it, which basically states that if the substitution for a template parameter fails the following code will be excluded from compilation rather than causing an error. What I haven't found out if the type_trait argument responsible for enabling/disabling the method has to be merged into the class template argument list like I did above, or if it is legal/possible to provide the type trait arguments in a seperate template argument list. In this case I guess it is impossible because the enable_if statement tests the classes template arguments which have to be declared/valid in this context.
Just in case you use really sophisticated type trait magic a more elaborate comment on that part is greatly appreciated.
The annoying part here is that the string version needs to access a member variable. So one way around that is to put the members in the most base class:
template <typename TVal1, typename TVal2>
class Members {
protected:
TVal1 value1;
TVal2 value2;
};
Just outsource getMax() to a different type:
// pure case
template <typename TSize, typename TVal1, typename TVal2>
struct VirtualMax : Members<TVal1, TVal2> {
virtual TSize getMax() const = 0;
};
// integer case
template <typename TSize, typename TVal1, typename TVal2>
struct IntMax : Members<TVal1, TVal2> {
TVal1 getMax() const { return std::numeric_limits<TVal1>::max(); }
};
// string case
template <typename TSize, typename TVal1, typename TVal2>
struct StringMax : Members<TVal1, TVal2> {
size_t getMax() const {
return this->value1.max_size();
}
};
So then we write a type trait:
template <typename TSize, typename TVal1, typename TVal2>
using Base_t = std::conditional_t<
std::is_same<TVal1, std::string>::value,
StringMax<TSize, TVal1, TVal2>,
std::conditional_t<
std::is_arithmetic<TVal1>::value,
IntMax<TSize, TVal1, TVal2>,
VirtualMax<TSize, TVal1, TVal2>
>
>;
And then use that alias:
template <typename TSize, typename TVal1, typename TVal2>
class AbstractBase
: Base_t<TSize, TVal1, TVal2>
{ };
After some tinkering and thanks to some ideas Barry gave me with his post above I took another shot at the problem myself. While Barrys answer provides a solution to the actual question I'd go and reply to myself to the question with "You don't.". The why Barry and me discussed in the comments:
The design gets complex
You clutter up your class hierarchy with lots of helper classes and structs that have no relevance for the actual project but exist purely out of architectural reasons to make the method selection based on type traits work.
So the much cleaner shot at this problem would be to keep the "AbstractBase" class purely abstract and combine type traits with inheritance deriving an ArithmeticBase class and a StringBase class using type traits to validate they only take valid template arguments. A solution could look like this:
#include <limits>
#include <string>
#include <type_traits>
#ifndef ABSTRACTBASE_H
#define ABSTRACTBASE_H
template <typename TSize,
typename TVal1,
typename TVal2>
class AbstractBase {
public:
virtual ~AbstractBase() {};
virtual TSize getMax() const = 0;
protected:
TVal1 value1;
TVal2 value2;
};
#endif //ABSTRACTBASE_H
#ifndef ARITHMETICBASE_H
#define ARITHMETICBASE_H
#include <limits>
#include <type_traits>
#include "AbstractBase.h"
template <typename TSize,
typename TVal1,
typename TVal2 = typename std::enable_if<std::is_arithmetic<TVal1>::value>::type>
class ArithmeticBase : public AbstractBase<TSize, TVal1, TVal2>
{
public:
virtual ~ArithmeticBase() {};
virtual TSize getMax() const { return std::numeric_limits<TVal1>::max(); };
};
#endif //ARITHMETICBASE_H
#ifndef STRINGBASE_H
#define STRINGBASE_H
#include <limits>
#include <type_traits>
#include <string>
#include "AbstractBase.h"
template <typename TSize,
typename TVal1,
typename TVal2 = typename std::enable_if<std::is_same<TVal1, std::string>::value>::type>
class StringBase : public AbstractBase<TSize, TVal1, TVal2>
{
public:
virtual ~StringBase() {};
virtual TSize getMax() const { return this->value1.max_size(); };
};
#endif //STRINGBASE_H
#include <string>
#include <iostream>
#include "ArithmeticBase.h"
#include "StringBase.h"
int main()
{
ArithmeticBase<int, int, int> arthBase;
StringBase<std::size_t, std::string, long> alphaBase;
std::cout << arthBase.getMax() << std::endl;
std::cout << alphaBase.getMax() << std::endl;
}

Are members of a class template instantiated when the class is instantiated?

Supposedly members of a template class shouldn't be instantiated unless they are used.
However this sample seems to instantiate the do_something member and the enable_if fails (which would be expected if we'd instantiated it - but AFAIK we did not).
Am I missing something really basic here?
#include <string>
#include <boost/utility.hpp>
struct some_policy {
typedef boost::integral_constant<bool, false> condition;
};
struct other_policy {
typedef boost::integral_constant<bool, true> condition;
};
template <typename policy>
class test {
void do_something(typename boost::enable_if<typename policy::condition>::type* = 0) {}
};
int main() {
test<other_policy> p1;
test<some_policy> p2;
}
coliru
From C++11 14.7.1/1:
The implicit instantiation of a class template specialization causes the implicit
instantiation of the declarations, but not of the definitions or default arguments, of the class member functions
So the function declaration is instantiated; that fails since it depends on an invalid type.
(Unfortunately, I don't have any historic versions of the standard to hand, but I imagine this rule was similar in C++98)
Mike Seymour already answered why it doesn't work, here's how to workaround it:
#include <string>
#include <boost/utility.hpp>
struct some_policy {
typedef boost::integral_constant<bool, false> condition;
};
struct other_policy {
typedef boost::integral_constant<bool, true> condition;
};
template <typename policy>
class test {
private:
template<typename P>
void do_something_impl(typename boost::enable_if<typename P::condition>::type* = 0) {}
public:
void do_something()
{
do_something_impl<policy>();
}
};
int main() {
test<other_policy> p1;
test<some_policy> p2;
}
Quick rule of thumb: If you want to do SFINAE, you need a member function template.
SFINAE happens only on template function/method (here, it is your class which is template),
You may do in C++11 (default template parameter for function/method):
template <typename policy>
class test {
template <typename T = policy>
void do_something(typename boost::enable_if<typename T::condition>::type* = 0) {}
};
You may alternatively use specialization, something like
template <bool> struct helper_do_something {};
template <> struct helper_do_something<true>
{
void do_something() { /* Your implementation */ }
};
template <typename policy>
class test : helper_do_something<T::condition::value>
{
// do_something is inherited (and it is present only when T::condition::value is true)
};

How to create new typename from the typename pass in a template class

Suppose I am having a template class
template <class DATA>
class Stack {
//Some implementation
}
Inside this stack class I am calling a utility class which is also template. But datatype its handling is of type UltityDATA. That is if we create the object of class stack using following code
stack<MyData> s
Internally it should call UltityMyData. I dont want to expose UltityMyData stucture to the clients. I have already written implementation for coverting MyData to UltityMyData . Only My requirement is how to convert DATA typename to UtilityDATA typename when I am calling my library class.
I have wrritten following code as per your suggestion
#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>
using namespace std;
struct RTI
{
int a;
};
struct DDSRTI
{
int b;
};
// other specialization you might need in the future
template<class Data>
struct DDS
{
typedef DDSData type;
};
template <class T>
class MyStack {
private:
T a;
public:
MyStack()
{
// cout<< a;
}
};
#define STACK(T) Stack<DDS##T>
template <class T>
class Stack {
private:
Stack<T> a;
STACK(T) b;
public:
Stack()
{
///cout<< a;
}
};
But I am getting error as error: 'DDST' was not declared in this scope
Basically preprocessor only appending two values and creating a new type. As per my understanding template will be convert at the time of compilation. DDS#T its taking as a new data type not as template type.
You can have a struct specializing a type definition according to your needs
// non specialized type
template<typename T>
struct UtilType {};
// specialization for DATA
template<>
struct UtilType<DATA>
{
typedef UtilityDATA type;
};
// other specialization you might need in the future
template<>
struct UtilType<NewType>
{
typedef UtilityNewType type;
};
You would then use this helper class as so
template<typename T>
class Stack
{
// .....
typedef typename UtilType<T>::type dataType; //converts DATA typename to UtilityDATA
// .....
}
You could use a traits pattern:
template <class DATA, class TRAITS>
class Stack
{
//Some implementation
}
and instanciate like this:
stack<MyData, UtilityMyData> s;
However, this will require your users to explicitly name the utility class. If you don't mind using the pre-processor you could use a macro:
#define STACK(T) Stack<T, Utility##T>
And then you'd write:
STACK(MyData) s;
It's not pretty, but it might be acceptable to your users
Maybe you can just move it to some internal template structure?
template <class DATA>
class Stack {
public:
template <class Data>
struct UtilData {
template <class... Args>
UtilData(Args&&... args) : d{std::forward<From>(args)...} {}
// other operators
Data d;
};
void push(DATA&& d) {
s.push(UtilData<DATA>{d});
}
std::stack<UtilData<DATA>> s;
};
Update: Sorry, I misunderstood your question. For some concrete types MyData and UtilMyData you can use boost::mpl::map:
using boost::mpl::pair;
using boost::mpl::map;
using boost::mpl::at;
typedef map<pair<SomeOther, Some>/*, other pairs of types here*/> TypeMap;
at<TypeMap, SomeOther>::type s; // s has type Some

CRTP with base class trying to get the return type of a derived class member: invalid use of incomplete type

Consider the following code (it's for example purpose only):
#include <iostream>
#include <type_traits>
#include <array>
template <
class Crtp,
class Vector = typename std::decay<decltype(std::declval<Crtp>().data())>::type,
class Scalar = typename std::decay<decltype(std::declval<Crtp>().data(0))>::type
>
struct Base
{;};
template <
class Vector = std::array<double, 3>,
class Scalar = typename std::decay<decltype(std::declval<Vector>()[0])>::type
>
struct Derived
: public Base<Derived<Vector, Scalar>>
{
Vector _data;
inline Vector& data() {return _data;}
inline const Vector& data() const {return _data;}
inline Scalar& data(const unsigned int i) {return _data[i];}
inline const Scalar& data(const unsigned int i) const {return _data[i];}
};
int main()
{
Derived<> d;
return 0;
}
It returns the following error:
main.cpp: In instantiation of 'struct Derived<>':
main.cpp:28:14: required from here
main.cpp:16:8: error: invalid use of incomplete type 'struct Derived<>'
main.cpp:16:8: error: declaration of 'struct Derived<>'
Is there a way to solve this (without using typedefs and only using templates)?
This is pretty messy, since Derived isn't complete when template argument deduction happens for Base. I assume the obvious answer - pass Vector and Scalar explicitly - is unsatisfactory. How about:
template <template <class, class> class Derived,
class Vector, class Scalar>
struct Base {};
template <class Vector, class Scalar>
struct Derived : Base<Derived, Vector, Scalar> {};
Why the strange restriction to not use typedef? I find:
template <class Vector>
using ScalarTypeOf =
typename std::decay<decltype(std::declval<Vector>()[0])>::type;
template <class Crtp>
using VectorTypeOf =
typename std::decay<decltype(std::declval<Crtp>().data())>::type;
template <class Crtp>
struct Base {
using Vector = VectorTypeOf<Crtp>;
using Scalar = ScalarTypeOf<Vector>;
};
template <class Vector>
struct Derived : public Base<Derived<Vector>> {
using Scalar = ScalarTypeOf<Vector>;
};
to be a bit more readable.