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();
Related
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)
{
}
};
};
Say I have this (stuck with C++03).
template <class T, int S>
class FiniteMap
{
public:
class Iterator {};
class Entry {};
};
class Foo {};
template <class T, int S>
class FooMap : public FiniteMap<T,S>
{
public:
void bar()
{
FooMap<T,S>::Iterator iter;
FooMap<T,S>::Entry entry;
}
};
int main()
{
return 0;
}
I want to typedef FooMap<T,S>::Iterator and FooMap<T,S>::Entry but if I try this:
typedef FooMap<T,S>::Iterator FooIterator;
I get "error: ‘T’ was not declared in this scope". If I try putting template parameters on it:
typedef
template <class T, int S>
FooMap<T,S>::Iterator FooIterator;
I get "error: expected unqualified-id before ‘template’".
I have resorted to using a #define:
#define FooIterator typename FooMap<T,S>::Iterator
This seemed to work (although it doesn't work on Online C++ Compiler).
Seems kind of hackish though.
Any ideas?
C++11 has `using for this :)
When I tried on C++03, I got the error "need typename before FiniteMap as it is a dependent scope...
Thus:
template <class T, int S>
class FiniteMap {
public:
class Iterator {};
class Entry {};
};
class Foo {};
template <class T, int S>
class FooMap : public FiniteMap<T, S> {
public:
typedef typename FiniteMap<T, S>::Iterator FooIterator;
typedef typename FiniteMap<T, S>::Entry FooEntry;
void bar()
{
FooIterator iter;
FooEntry entry;
}
};
int main()
{
FooMap<int, 3> test;
return 0;
}
On GodBolt
With
typedef FooMap<T,S>::Iterator FooIterator;
compiler complains about T (and probably S) not being declared - and I have to agree.
If you want to keep T abstract, then you are stuck with using the parameterised template.
But I think you actually want to typedef a "short" for the specific case of T=Foo and S=5.
That can be done this way
/* ... start of your file */
class Foo {};
typedef FooMap<Foo,5>::Iterator FooIterator;
int main()
{
}
I have the following template class. I need to specialize the alloc function for some specific outT case.
template <typename inT, typename outT>
class Filter {
public:
typedef inT InputType;
typedef outT OutputType;
struct Options {
int a, b, c;
};
virtual void alloc();
};
// Partial template specialization for SpecificOutputType
template < typename inT>
class Filter<inT, SpecificOutputType> {
virtual void alloc();
};
This results in the Options class and OutputType being undefined for gcc, example:
using FilterType = Filter<SomeIn, SpecificOutputType>:
FilterType::Options options;
Results in
error: ‘Options’ is not a member of `Filter<SomeIn, SpecificOutputType>`
This error does not happen if I use some type other than SpecificOutputType.
How can I solve this?
Every template specialization is independent, they're irrelevant with the primary template, so you have to also define Options, OutputType and other necessary members in the template specialization explicitly.
Members of partial specializations are not related to the members of the primary template.
You could make a common base class template to avoid code duplication.
template <typename inT, typename outT>
class FilterBase {
public:
typedef inT InputType;
typedef outT OutputType;
struct Options {
int a, b, c;
};
};
template <typename inT, typename outT>
class Filter : public FilterBase<inT, outT> {
public:
virtual void alloc();
};
// Partial template specialization for SpecificOutputType
template <typename inT>
class Filter<inT, SpecificOutputType> : public FilterBase<inT, SpecificOutputType> {
virtual void alloc();
};
Sorry about the vague title.
I was trying to fix a problem in a fairly large codebase. The fix requires me to have ChildClass and ChildListElementClass both supplied with the other as a template argument. I believe the problem I'm having is that myType in ParentListElementClass is not overwritten with typedef ChildClass<ChildListElementClass> myType; in the derived class ChildListElementClass.
How can I make this work? Thank you very much!
Compiler says:
Error 1 error C2664: 'void ParentListElementClass<ChildClass>::AddX(ParentClass<ParentListElementClass<ChildClass>> *)' : cannot convert argument 1 from 'ParentClass<ChildListElementClass> *const ' to 'ParentClass<ParentListElementClass<ChildClass>> *'
I wrote the following minimal testcase to demonstrate my problem:
#include "stdafx.h"
#include <iostream>
template <class ElementType>
class ParentClass;
template <class ParentType>
class ParentListElementClass
{
public:
ParentListElementClass(){};
~ParentListElementClass(){};
typedef ParentClass<ParentListElementClass> myType;
myType *x;
void AddX(myType *m){
m->speak();
};
};
class ChildListElementClass;
template <class ElementType>
class ParentClass
{
public:
ParentClass(){};
~ParentClass(){};
ElementType m;
void DoSomething() {
std::cout << "ParentList\n";
m.AddX(this);
}
virtual void speak(){ std::cout << "Parent\n";}
};
class ChildClass;
class ChildListElementClass : public ParentListElementClass<ChildClass>
{
public:
ChildListElementClass(){};
~ChildListElementClass(){};
};
class ChildClass : public ParentClass<ChildListElementClass>
{
public:
ChildClass(){};
~ChildClass(){};
void speak(){ std::cout << "Child\n"; }
};
int _tmain(int argc, _TCHAR* argv[])
{
ChildClass Child;
ChildListElementClass ChildListElement;
Child.DoSomething();
return 0;
}
Edit: Working Version with help from itachi:
template <typename ElementType, typename ListType> class ParentListClass;
template <typename ElementType, typename ListType>
class ParentElementClass
{
typedef ParentListClass<ElementType, ListType> myType;
};
template <typename ElementType, typename ListType>
class ParentListClass{};
class ChildListClass;
class ChildElementClass : public ParentElementClass<ChildElementClass, ChildListClass>{};
class ChildListClass : public ParentListClass<ChildElementClass, ChildListClass>{};
I'm not sure I completely understand your question, but no matter how I think of it, changing ParentListElementClass appears hard to avoid. You could try something on these lines..
template<typename T, typename U>
struct MyTypedefCase
{
typedef T<U> _type;
};
Then rewrite ParentListElementClass as
template <class ParentType, typename T, typename U>
class ParentListElementClass
{
//typedef ParentClass<ParentListElementClass> myType; Change this to below line
typedef typename MyTypedefCase<T,U>::_type myType;
//Rest of your code
};
and
class ChildListElementClass : public ParentListElementClass<ChildClass,ChildClass,ChildListElementClass>
I have never done something this complex with templates So I don't gurantee that it would work but if I had to go about it with minimal changes this would be the way. Perhaps someone could look into this solution and offer changes or imprvement.
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)
};