Enum inside a templated class - c++

Let's say I have a class Class, which has an associated enum member Enum. The enum only makes sense in the context of this class, and therefore it is specified inside it. Then you can just call Class::Enum::Something from outside of the class, which is fine.
class Class
{
public:
enum class Enum : uchar
{
Something
}
}
However, if the class Class is templated, you cannot do Class::Enum::Something, but you have to Class<T>::Enum::Something (or Class<>::Enum::Something if T has some default type).
template <typename T = double>
class Class
{
public:
enum class Enum : uchar
{
Something
}
}
The Enum has to be the same for all Ts, since it's just a simple enum, but the T always has to be specified anyway.
My question is - is there a clever way of avoiding this?

It is essential to understand that the wrapped enum type is a different type for different specializations of Class.
#include <type_traits>
template <typename T = double>
struct S
{
enum class E : int { a };
};
static_assert(!std::is_same_v<S<>::E, S<int>::E>); // !!!
It seems like you want this to actually be the same type, in which case you could break it out into a separate class and use private implementation inheritance to expose it via the class template specializations:
#include <type_traits>
namespace detail {
struct Base {
enum class E : int { a };
};
} // namespace detail;
template <typename T = double>
struct S : private detail::Base
{
using Base::E;
};
static_assert(std::is_same_v<S<>::E, S<int>::E>); // OK
However if you are set on supplying this enum as a member (alias declaration above) of the various class template specializations, you will need to qualify which specialization you refer to.
S<>::E;
S<int>::E;
The root problem you seem to want to solve is scoping, in which case you may use a namespace instead of class to wrap the associated enum:
namespace my_lib {
template <typename T = double>
struct S {};
enum class E : int { a };
} // namespace my_lib

Often it is more convenient to move everything that does not depend on the tempalte argument to a non-template base class:
#include <iostream>
class Base {
public:
enum class Enum
{
Something
};
};
template <typename T = double>
class Class : public Base
{
};
int main() {
std::cout << (Class<>::Enum::Something == Class<int>::Enum::Something);
}

Related

How to declare a member in a base template class where the type is dependent of the derived class?

Given a base class using CRTP, I'm looking at declaring a member in the base template class where the type is dependent of the derived class.
While the following works as intended:
template <class T> class BaseTraits;
template <class T> class Base {
using TypeId = typename BaseTraits<T>::TypeId;
TypeId id;
public:
Base() { id = 123; }
TypeId getId() { return id; }
};
class Derived;
template <> class BaseTraits<Derived> {
public:
using TypeId = int;
};
class Derived : public Base<Derived> {};
int main(int argc, char ** argv) {
Derived foo;
return foo.getId();
}
I wonder if I could simplify the implementation. I could add a second template parameter to the Base template, and make BaseTraits simpler or even get rid of it. However the above snippet is already an attempt to remove the second template parameter. I'm looking at solutions that doesn't involve a second template parameter for Base.
I've tried something like the following but it doesn't compile:
error: invalid use of incomplete type 'class Derived'
template <class T> class Base {
using TypeId = typename T::TypeId;
TypeId id;
public:
Base() { id = 123; }
TypeId getId() { return id; }
};
class Derived : public Base<Derived> {
public:
using TypeId = int;
};
int main(int argc, char ** argv) {
Derived foo;
return foo.getId();
}
UPDATE:
I'm limited to c++14.
Base must be a template.
Performance is a must.
Is it possible to make a member type directly dependent on the derived class? Taking appart the result type of a member function declared with auto (deduced return type), it is not possible.
So the use of a type-trait as you do in your solution is the best and only solution.
The reason is that a base class must be a complete type when the derived class is defined: the compiler must first instantiate and parse the base class definition before it parses the derived class definition, C++ standard N4140 [derived.class]/2 (bold is mine):
The type denoted by a base-type-specifier shall be a class type that is not an incompletely defined class;[...]
What about something like this:
template <typename T, typename TypeId> class Base
{
private:
TypeId id;
public:
Base() { id = 123; }
TypeId getId() {return id;}
};
class Derived : public Base<Derived, int> {};
This is kind of simplified, but you pay some price for it.
#include <any>
template <class T> class Base {
std::any id; // expensive, but cannot have T::TypeId here
public:
Base() : id(123) {}
auto getId() {
return std::any_cast<typename T::TypeId>(id);
} // T::TypeId is OK inside a member function
};
class Derived : public Base<Derived> {
public:
using TypeId = int;
};
Why not reversing the class hierarchy?
template <class T>
class Base : T {
using TypeId = typename T::TypeId;
TypeId id;
public:
Base() { id = 123; }
TypeId getId() { return id; }
};
struct BasicDerived {
using TypeId = int;
};
using Derived = Base<BasicDerived>;
Actually, I thought some more... this isn't too unpleasant:
You could have a binding struct, could even be written as a macro, declared just before the real class.
The binding struct defines the enum and an incomplete typedef to the real class.
The template is defined before all of that, but uses typename to defer its dependency, but it is instanced by the real class and only dependant on the binding struct
template <class ThatClassWrapper>
class MyBase
{
protected:
typedef typename ThatClassWrapper::TypeId TypeId;
typedef typename ThatClassWrapper::RealClass ThatClass;
TypeId typeIdValue;
TypeId GetTypeId() { return typeIdValue; }
std::vector<ThatClass*> storage;
};
class SomeClass;
namespace TypeIdBinding
{
struct SomeClass
{
enum TypeId
{
hello, world
};
typedef ::SomeClass RealClass;
};
}
class SomeClass: public MyBase<TypeIdBinding::SomeClass>
{
public:
bool CheckValue(TypeId id)
{ return id == typeIdValue; }
};
Note that the real class is using TypeId as defined in the template base, and the named members are not directly visible. You could fix that by having the template Base derive from the binding struct (confirmed that it compiles that way). though I actually like that in c++11 you can export or typedef just the enum typename from another namespace and use that type name as a prefix for the enum members, helping to avoid name pollution.
To be honest you have hit the wall of hard circular dependencies.
Any way out will be smelly.
Two template arguments seems like a small price in the end.
Could you declare a dummy template class that takes Derived and TypeID? I don't think it gains you anything, though.
Is TypeID:Derived a 1:1 mapping? Would it feel better to over-represent that 1:1 mapping with another helper template to back-look-up Derived from TypeID? Note that TypeID would need to be defined outside the Derived class to do this.
Does TypeID really need to be defined inside the class? Could it leach off the passed-in definition in Base to support the existing use of the internal typedef?
Can you double-include? Split or macriose your definition of derived so that typeid is in a base class definition that can be included before the template? This DerivedBase could be declared in a namespace and contain a typedef link back to the full Derived class so Base can find it for references.

Template only for smart pointer

Hi I am not sure that this is possible since but I thought of asking since there might be better ways of achieving something similar that I am not aware of.
For simplicity lets just consider that VectorT is
template<class T>
class VectorT: private std::vector<T>`
An attempt to what I wanted to have is something along the lines of.
namespace detail
{
template<class SmartPtr>
class MyClassVectorBase : public VectorT<SmartPtr>
{
public:
MyClassVectorBase() = default;
// all common functions of MyVectorView and MyVector
};
}
using MyClassVectorView = detail::MyClassVectorBase<nonstd::observer_ptr<SomeClass>>;
class MyVector : public detail::MyClassVectorBase<std::unique_ptr<SomeClass>>
{
// only functions related to the actual owner vector
};
What I am hoping is that MyClassVectorBase can be templated only on the smart pointer type and only accept SomeClass.
I thought that it might be possible with a specialization but I got no idea what the syntax for something like that would be
template<class T, class SmartPtr>
class MyClassVectorBase : public VectorT<SmartPtr<T>>
{
};
template<SomeClass T, typename SmartPtr>
class MyClassVectorBase : public VectorT<SmartPtr<T>>
{
};
Is something like that even possible ?
Edited:
Ok let me try to explain this and the logic behind it. I need to have a VectorT of Foo objects. Only Foo and nothing else.
In one case the class will be the owner of the objects and have a few extra functions.
Since it is the owner it will be class MyClassVector : public VectorT<std::unique_ptr<Foo>>
Then I have to somehow operate on these objects but these wont be owned.
The ownership is single and will always outlive the object that I will operate on so no need for shared_ptr.
So Then I guess my class will be a "View class" MyClassVectorView : public VectorT<std::observer_ptr<Foo>>
Instead of observer_ptr it could as well be say raw ptr but the intent is better with it.
Now MyClassVectorView will have all identical functions with MyClassVector which is why I think that I would be inheriting from it.
To do so I need to have a base class that will accept both unique_ptr and observer_ptr.
Then I can avoid duplication so long as I can do MyClassVector : public MyClassVectorView<std::unique_ptr<Foo>>
The alterantive would be have one class and detect with SFINAE if the template parameter is a unique_ptr and then enable the extra functions. This would avoid the extra inheritance.
Not sure about what you want to obtain but I suspect that you need template template parameters.
I suppose you could declare (but not define) MyClassVectorBase as receiving a single template typename parameter
template <typename>
class MyClassVectorBase;
and next define a specialization template-template based; something like
template <template<typename...> class SmartPtr, typename Foo>
class MyClassVectorBase<SmartPtr<Foo>> : public VectorT<SmartPtr<Foo>>
{
public:
MyClassVectorBase() = default;
void doSomething(){}
void doSomething2(){}
};
If Foo isn't a template parameter, but is the Foo struct, you can write
template <template<typename...> class SmartPtr>
class MyClassVectorBase<SmartPtr<Foo>> : public VectorT<SmartPtr<Foo>>
{
public:
MyClassVectorBase() = default;
void doSomething(){}
void doSomething2(){}
};
Your example modified and integrated (with a main() and a dummy observer_ptr)
#include <iostream>
#include <string>
#include <vector>
#include <memory>
namespace nonstd
{
template <typename T>
struct observer_ptr
{ };
}
template <class T>
class VectorT
{
public:
// expose nececssary functions
private :
std::vector<T> container_;
};
struct Foo{
double x;
};
template <typename>
class MyClassVectorBase;
// this class should only accept smart pointers of Foo
template <template<typename...> class SmartPtr, typename Foo>
class MyClassVectorBase<SmartPtr<Foo>> : public VectorT<SmartPtr<Foo>>
{
public:
MyClassVectorBase() = default;
void doSomething(){}
void doSomething2(){}
};
using MyClassVectorView = MyClassVectorBase<nonstd::observer_ptr<Foo>>;
class MyVector : public MyClassVectorBase<std::unique_ptr<Foo>>
{
// function only for this class but still inheriting all MyClassVectorBase stuff
};
int main ()
{
}

C++ map a template derived class

Hi I have a the following structures and data types:
enum EWorkerType
{
WorkerType1,
WorkerType2,
LastWorker
};
template<class DerivedType>
struct CHandlerMethod
{
};
struct CFunctorA : public CHandlerMethod<CFunctorA>
{
};
struct CFunctorB : public CHandlerMethod<CFunctorB>
{
};
template<class TFunctor>
struct CWorkerHandler
{
CHandlerMethod<TFunctor>* m_HandlerMethod;
};
typedef std::vector<CWorkerHandler<CFunctorA>*> WorkerA;
typedef std::vector<CWorkerHandler<CFunctorB>*> WorkerB;
I need a direction to create a const map between EWorkerType::WorkerType1 to WorkerA and EWorkerType::WorkerType2 to WorkerB.
I tried this direction
struct WorkersMapping
{
WorkersMapping()
{
m_WorkersMapper.insert(EWorkerType::WorkerType2, CFunctorA::value_type());
}
static std::map<EWorkerType, ???> m_WorkersMapper;
};
static WorkersMapping m_WorkersMapping;
You may use something like (for compile time):
template <EWorkerType> struct WorkersMapping;
template <> struct WorkersMapping<WorkerType1>
{
using type = WorkerA;
};
template <> struct WorkersMapping<WorkerType2>
{
using type = WorkerB;
};
or if your enum values is correctly chosen, something like:
template <EWorkerType E> struct WorkersMapping
{
using type = typename std::tuple_element<E, std::tuple<WorkerA, WorkerB>>::type;
};
Wrap WorkerA and WorkerB into respective classes derived from a common base class, in addition to also inheriting from std::vector (multiple inheritance). Then simply define your map value as a smart pointer to the base class (or a regular pointer if you want to put the worker objects on the stack).

Templated data types with derived classes

Let's say I have the following:
class Base
{
protected:
Base() { }
};
class A : public Base
{
};
class B : public Base
{
};
Now suppose I do this with a template:
TemplatedClass<Base> *generic = new TemplatedClass<A>();
It doesn't work, and I believe I understand why, but I'd like to know if I can do something equivalent. I have several template specializations of the form
typedef TemplatedClass<A> ASpec;
typedef TemplatedClass<B> BSpec;
typedef TemplatedClass<C> CSpec;
I have a single variable whose type I'd like to defer until runtime, so that I can dynamically assign it like
if(condition1)
generic = new ASpec();
else if(condition2)
generic = new BSpec();
Is there any way to go about this? I don't have the ability to change the fact that the classes are templated and not inheriting from a base class, or I'd just do that.
This is not possible in C++.
The fact that A derives from Base doesn't mean that TemplatedClass<A> derives from TemplatedClass<Base>.
See this Stack Overflow post for alternatives:
Conversion from STL vector of subclass to vector of base class
You can derive TemplatedClass<T> from TemplatedClass<Base>, either by specialising if for Base, or by providing a dummy class like this:
struct Dummy {};
template <typename T>
struct BaseClass<T> {
typedef TemplatedClass<Base> Type;
};
template <>
struct BaseClass<Base> {
typedef Dummy Type;
};
template <typename T>
struct TemplatedClass : BaseClass<T>::Type
{
//...
};

member template specialization and its scope

It appears to me that C++ does not allow member template specialization in any scope other than namespace and global scope (MS VSC++ Error C3412). But to me it makes sense to specialize a base class's primary member template in the derived class because that is what derived classes do - specialize things in the base class. For instance, consider the following example:
struct Base
{
template <class T>
struct Kind
{
typedef T type;
};
};
struct Derived : public Base
{
/* Not Allowed */
using Base::Kind;
template <>
struct Kind <float>
{
typedef double type;
};
};
int main(void)
{
Base::Kind<float>::type f; // float type desired
Derived::Kind<float>::type i; // double type desired but does not work.
}
My question is why isn't it allowed?
I get what you're trying to do, but you are not doing it right. Try this :
struct Base{};
struct Derived{};
// Original definition of Kind
// Will yield an error if Kind is not used properly
template<typename WhatToDo, typename T>
struct Kind
{
};
// definition of Kind for Base selector
template<typename T>
struct Kind<Base, T>
{
typedef T type;
};
// Here is the inheritance you wanted
template<typename T>
struct Kind<Derived, T> : Kind<Base, T>
{
};
// ... and the specialization for float
template<>
struct Kind<Derived, float>
{
typedef double type;
};
My question is why isn't it allowed?
From my copy of the draft it appears that the following puts the above restriction:
In
an explicit specialization declaration for a class template, a member of a class template or a class member
template, the name of the class that is explicitly specialized shall be a simple-template-id.
The workaround is to specialize the enclosing class.
I will "ignore" the standard specifications and try a logical argument:
If you have two classes:
class A
{
struct S { };
};
class B: public A
{
struct S { };
};
A::S and B::S are two different types. Extending the logic to the template specializations, when you try to specialize an inner class declared in base class through an inner class in derived class, you actually are trying to define a different type, with the same name (but another naming scope).