Can anyone explain why this code gives the error:
error C2039: 'RT' : is not a member of 'ConcreteTable'
(at least when compiled with VS2008 SP1)
class Record
{
};
template <class T>
class Table
{
public:
typedef typename T::RT Zot; // << error occurs here
};
class ConcreteTable : public Table<ConcreteTable>
{
public:
typedef Record RT;
};
What can be done to fix it up. Thanks!
Update:
Thanks pointing out the issue, and for all the suggestions. This snippet was based on code that was providing an extensibility point within an existing code base, and the primary design goal was reducing the amount of work (typing) required to add new extensions using this mechanism.
A separate 'type traits' style class actually fits into the solution best. Especially as I could even wrap it in a C style macro if the style police aren't looking!
That's because the class ConcreteTable is not yet instantiated when instantiating Table, so the compiler doesn't see T::RT yet. I'm not really sure how exactly C++ standard handles this kind of recursion (I suspect it's undefined), but it doesn't work how you'd expect (and this is probably good, otherwise things would be much more complicated - you could express a logical paradox with it - like a const bool which is false iff it is true).
Fixing
With typedefs, I think you cannot hope for more than passing RT as additional template parameter, like this
template <class T, class RT>
class Table
{
public:
typedef typename RT Zot;
};
class ConcreteTable : public Table<ConcreteTable, Record>
{
public:
typedef Record RT;
};
If you don't insist on RT being available as Table<>::Zot, you can put it inside a nested struct
template <class T>
class Table
{
public:
struct S {
typedef typename RT Zot;
};
};
class ConcreteTable : public Table<ConcreteTable>
{
public:
typedef Record RT;
};
Or even external traits struct
template <class T>
struct TableTraits<T>;
template <class T>
struct TableTraits<Table<T> > {
typedef typename T::RT Zot;
};
If you only want the type be argument/return type of a method, you can do it by templatizing this method, eg.
void f(typename T::RT*); // this won't work
template <class U>
void f(U*); // this will
The point of all these manipulations is to postpone the need for T::RT as late as possible, particularly till after ConcreteTable is a complete class.
Why not just do something like this?
class Record
{
};
template <class T>
class Table
{
public:
typedef typename T Zot;
};
class ConcreteTable : public Table<Record>
{
public:
typedef Record RT; //You may not even need this line any more
};
The problem is that ConcreteTable is defined in terms of Table, but you can't define Table without a definition of ConcreteTable, so you've created a circular definition.
It also looks like there may be an underlying problem in the way you are designing your class hierarchy. I am guessing what you are trying to do is provide ways of manipulating a generic record type in your definition of Table, but leaving it up to ConcreteTable to define what the record type is. A better solution would be to make the record type a parameter of the Table template, and ConcreteTable a direct subclass:
class Record {};
template <class T>
class Table {
public:
typedef T RT;
};
class ConcreteTable : public Table<Record> {
};
Now you eliminate the circular dependency, and Table is still abstracted based on the type of record.
Notice that what you want to do can't be allowed by the compiler. If it was possible, you would be able to do this:
template <class T>
class Table
{
public:
typedef typename T::RT Zot;
};
class ConcreteTable : public Table<ConcreteTable>
{
public:
typedef Zot RT;
};
Which would be a kind of type-definition-infinite-loop.
The compiler blocks this possibility by requiring a class to be fully defined when one of its members needs to be used; in this case, the point of template instatiation for Table (the ancestors list in ConcreteTable) is before the definition of RT, so RT can't be used inside Table.
The workaround requires having an intermediate class to avoid the mutual dependence, as others already stated.
When Table<ConcreteTable> is instantiated, ConcreteTable is still an incomplete type. Assuming you want to stick with CRTP you could just pass Record as an additional template parameter like:
class Record
{
};
template <class T, class U>
struct Table
{
typedef U RT;
};
struct ConcreteTable : Table<ConcreteTable, Record>
{
};
Also note that you can access ConcreteTable as a complete type in any member functions in Table because they are instantiated only later when used. So this would be ok:
struct Record
{
};
template <class T>
struct Table
{
void foo()
{
typedef typename T::RT Zot;
Zot a; // ...
}
};
struct ConcreteTable : Table<ConcreteTable>
{
typedef Record RT;
};
int main()
{
ConcreteTable tab;
tab.foo();
}
I think everyone else has covered it pretty well, I just wanted to add that I think it's bad practice to inherit from a template of self and then try to patch things round to make it work. I would take a different approach and have the record type (RT) as the parameters instead of ConcreteTable itself. If you've ever looked at the std::iterator class, it uses this exact approach:
template <class Category, class T, class Distance = ptrdiff_t,
class Pointer = T*, class Reference = T&>
struct iterator {
typedef T value_type;
typedef Distance difference_type;
typedef Pointer pointer;
typedef Reference reference;
typedef Category iterator_category;
};
When a subclass inherits from iterator, it does this:
struct ExampleIterator : std::iterator<std::forward_iterator_tag, Example>
Which is exactly what you want to do. Notice that the 'RecordType' fields are actually in the superclass, and passed in through template parameters. This is the best way to do it, it's in the standard library because of it.
If you want to do more specialisation of the ConcreteTable subclass, you can always override methods from Table, as well as using the template parameters.
you are trying to use class CponcreateTable as a template parameter before the class is fully defined.
The following equivalent code would work just fine:
class Record
{
};
template <class T> Table
{
public:
typedef typename T::RT Zot; // << error occurs here
};
class ConcreteTableParent
{
public:
typedef Record RT;
};
class ConcreteTable: public Table<ConcreteTableParent>
{
public:
...
};
Related
I need a template-of-template class, but the issue is, that I can't access the type of nested template:
template<template<class TParamPayload> class TMsg>
class ParameterBasedFilter : public IMsgFilter
{
public:
typedef TMsg<TParamPayload> ExpectedMessage;
typedef TParamPayload::otherType SomeOtherType;
};
And here is a usage (I want to pass only one template argument, without comma)
ParameterBasedFilter<SomeMessage<SomePayload>> filter;
There is an error inside ParameterBasedFilter:
error: 'TParamPayload' was not declared in this scope
typedef TMsg<TParamPayload> ExpectedMessage;
^
Is it possible at all to get the nested template type? I know, that code below will work
template<class TParamPayload, template<class> class TMsg>
class ParameterBasedFilter : public IMsgFilter
{
public:
typedef TMsg<TParamPayload> ExpectedMessage;
typedef TParamPayload::otherType SomeOtherType;
};
but then I have to pass 2 types to the template arguments:
ParameterBasedFilter<SomePayload, SomeMessage<SomePayload>> filter;
and it looks weird, because SomePayload is used twice.
Perhaps you're looking for partial specialization? That would allow the original syntax mentioned in your question:
template <typename> class ParameterBasedFilter;
template <template<class> class TMsg, typename TParamPayload>
class ParameterBasedFilter<TMsg<TParamPayload>> : public IMsgFilter
{
public:
typedef TMsg<TParamPayload> ExpectedMessage;
typedef TParamPayload::otherType SomeOtherType;
};
Usage is simple:
ParameterBasedFilter<SomeMessage<SomePayload>> filter;
No, you cannot. However you will should to pass
ParameterBasedFilter<SomePayload, SomeMessage> filter;
SomePayload will not be used twice.
Also, you should use typename when access to otherType
typedef typename TParamPayload::otherType SomeOtherType;
I am trying to set the type of the member of a class, without passing it through template argument.
In details:
// Forward declaration:
class A;
class B;
class Base
{
};
template <class T>
class Derived : public Base
{
private:
T2 var;
};
where T could be either class A or class B.
What I would like to do is for Derived<A> T2 is int (for instance) and for Derived<B> T2 is double (for instance). I would like to avoid the following solution:
template <class T1, class T2>
class Derived : public Base
{
private:
T2 var;
};
I want to avoid this because for Derived<A> there could be various possible combinations for T2: Derived<A,int>, Derived<A,double>, ...
What I want is that the type of T2 is unique for the entire Derived<A>.
Any idea how to solve that ?
Update: The comments show that the original problem you are trying to solve is not completely explained in the question. I'll leave the original answer nevertheless at the bottom of this answer.
You cannot have two Derived<A> with different types T2 for the var member. In addition, a variable defined by the User can not influence the type of the member variable. Variable values are set at runtime, types are determined at compiletime.
To store a type somehow defined by the user, you will have either have to restrict the variable to a set of known types or use one type that contains a serialized version of the variable's content. The set of known types is often used in the context of databases, where the fields can have one of several predefined types (e.g. String, Integer, Boolean, Double). The type for the member variable then could be a Boost.Variant, restricted to C++ representations of that type. Another application of "user defined types" are where the user of your program has to somehow define the layout and interpretation of the type and its object, for example if your program is the interpreter of some scripting language. In that case again a Boost.Variant (or something similar) can be of use, or, since the value is probably some user provided input, just store the serialized value in a string and interpret it every time you have to deal with it.
Original answer:
This is usually done via template metaprogramming, in this case a type function (sometimes, depending on the context, part of a traits or policy class):
template <class T>
struct DerivedMemVarType {
typedef double type; //default
};
template<>
struct DerivedMemVarType<A> {
typedef int type;
};
And then:
template <class T>
class Derived : public Base
{
typedef typename DerivedMemVarType<T>::type T2;
private:
T2 var;
};
You can also leave out the default, so that any instantiation of Derived for a type that you have not mapped in your function will give a compile error:
template <class T>
struct DerivedMemVarType; //default is not defined
template<>
struct DerivedMemVarType<A> {
typedef int type;
};
template<>
struct DerivedMemVarType<B> {
typedef double type;
};
//...
Derived<C> dc; // ...template error mess....
// --> error: invalid use of incomplete type 'struct DerivedMemVarType<C>'
if you do not have any type specific function call, you can use something like...
class A;
class B;
class Base
{
};
template <class T>
class Derived : public Base
{
public:
Derived(T startVal):var(startVal){}
private:
T var;
};
template <typename T>
Derived<T> MakeDerived(T initValue)
{
return Derived<T>(initValue);
}
and now you can use it the following and the compiler should know what type you are passing to the function.
int initialValue = 0;
auto derived = MakeDerived(initialValue);
I think you can create a separate class that just holds a typedef which you then specialize and use in your Derived class.
template<typename T>
class VarType {
public:
typedef int TheType;
}
template <>
class VarType<B> {
public:
typedef double TheType;
};
template <typename T>
class Derived : public Base {
private:
typename VarType<T>::TheType var;
};
As a simplified example, if I have the classes
template <class T, class U> class ProcessEvent
{
public:
ProcessEvent(T* t) : var1(t) { var2 = new U; }
Process() { var2->Process(var1); }
private:
T* var1;
U* var2;
};
class Foo
{
/*data*/
};
class FooProcessor
{
void Process(Foo* foo) {/*functionality*/}
};
class Bar
{
/*data*/
};
class BarProcessor
{
void Process(Bar* bar) {/*functionality*/}
};
So the class ProcessEvent can take have two different sets of template types,
ProcessEvent<Foo, FooProcessor>
ProcessEvent<Bar, BarProcessor>
However, the second template type FooProcessor and BarProcessor are directly implied by the first template type and are implementation details the user doesn't care about. My goal is to have the same functionality as above, but have ProcessEvent take only a single template parameter, Foo or Bar. Other than through specialization of ProcessEvent, can this be done?
I'm going to assume that you simplified for clarity and are reallyusing smart pointers or at least properly managing the memory.
The easiest way to do this is with a typedef in the first class:
class Foo
{
typedef FooProcessor Processor;
// Stuff.
};
Then in your template get rid of U and use typename T::Processor instead.
You can do this as follows:
template<typename T>
class Spec
{
};
template<>
class Spec<Foo>
{
typedef FooProcessor type;
};
template<>
class Spec<Bar>
{
typedef BarProcessor type;
};
Then use Spec<T>::type, with T=Bar or T=Foo, whenever you need BarProcessor and FooProcessor, respectively.
I would assume that a FooProcessor can only process Foo and a BarProcessor can only process Bar, but the other types could have more than one processor class. Thus you could do it intrusively:
class FooProcessor
{
public:
typedef Foo value_type;
};
class BarProcessor
{
public:
typedef Bar value_type;
};
You could use polymorphism:
template< typename T >
class Processor
{
public:
typedef T value_type;
virtual ~Processor() {}
virtual void process( value_type * ) = 0;
};
class FooProcessor : public Processor<Foo>
{
// implement process
};
You could use an adapter class like Matt Phillips's but in reverse, so it takes the process class as template parameter:
template<typename T>
class Spec
{
};
template<> class Spec<FooProcessor>
{
typedef Foo type;
};
template<> class Spec<Bar>
{
typedef BarProcessor type;
};
With intrusive typing and the Spec adapter typing your ProcessEvent template would take the processor type as parameter and derive the other one using value_type or type.
With polymorphism, your ProcessEvent would take the object type as parameter (Foo or Bar) and would be passed a processor that derives from Processor or Processor to process events.
If there are huge numbers of events to process and it is always processing them with the same object, the latter method would of course be slightly less efficient as it is processing through a v-table. It depends partly how long they take to process and whether the function that does it could be inlined.
I'm trying to create a list of objects, where each object also stores 'ownership' - ie, it knows which list holds it.
In a non-template situation, it's straightforward:
class FooList; // forward declaration
class FooItem
{
public:
FooList *owner;
...
};
class FooList: private std::list<FooItem>
{
...
};
However, the list class is a template, based on the contained object type, and I'm struggling to work out how to specify this. I reckon the FooItem class now needs to be a template because the type of 'owner' can vary:
template <class E> class FooItem
{
public:
std::list<E> *owner;
};
template <class E> class FooList: private std::list<E>
{
...
};
But, now given my two templates, how can I define the new types I want? The snippet below is what I think I need, but it gives "error: Multiple declaration for BarItem".
class BarItem;
typedef FooList<BarItem> BarList;
typedef FooItem<BarList> BarItem;
EDIT:
Thanks to those who pointed out the issue of std::list<E> instead of std::list<FooItem<E> >
EDIT 2:
Renamed classes to Base, Derived, BaseList, DerivedList.
My real problem was the 'circular typedef'. After some more tinkering, I think this will do what I require. It creates a 'real' BarItem class rather than just a typedef, but seems to at least compile now.
template <class E> class BaseList; // forward declaration
template <class E> class Base
{
public:
BaseList< Base<E> > *owner;
};
template <class E> class BaseList: private std::list< E >
{
};
// typedef Base<BaseList<Derived> > Derived; //This won't compile, unsurprisingly.
class Derived : public Base < BaseList<Derived> > // Surprisingly, this seems to.
{
...
};
typedef BaseList<Derived> DerivedList;
Does this seem to make sense? Is it a common idiom or something horrible?
Are you sure you didn't want:
template <class E> class FooItem
{
public:
std::list< FooItem<E> > *owner; // owned by a list of FooItem<E>, not raw E
};
template <class E> class FooList: private std::list< FooItem<E> > // is a list of FooItem<E>, not raw E
{
...
};
The error you are getting is because you forward declare the class BarItem but later try to redefine that name using typedef. Not sure what you're trying to accomplish, but you'll need to introduce a third name. Maybe you meant:
class Bar;
typedef FooItem<Bar> BarItem;
typedef FooList<Bar> BarList;
EDIT: The new code you've posted certainly compiles, but seems very awkward (for one thing, the naming seems really confusing). Perhaps you should ask a new question with a more concrete example of why you think you need an 'item which is an item of lists of itself' and see if others can come up with a less awkward design.
Is that last set of typedef statements correct? You posted this:
class BarItem;
typedef FooList<BarItem> BarList;
typedef FooItem<BarList> BarItem;
It's somewhat recursive, right? The first statement says there's a class BarItem that exists elsewhere. The second statement says that the type FooList<BarItem> (a list of BarItem objects) can also be referred to as BarList. The third statement says that the type FooItem<BarList> can also be referred to as BarItem, but BarItem was already defined as a type by the class BarItem statement.
So you're saying that BarItem is a type all to itself (via the class statement), but you're also saying that BarItem is an alias for the type FooItem<BarList>. Hence the conflict.
If you just want to generalize your first approach to a templated FooItem class, it would look like this:
template <class E> class FooList; // forward declaration
template <class E> class FooItem
{
public:
FooList<E> *owner;
...
};
template <class E> class FooList: private std::list< FooItem<E> >
{
...
};
If that is not what you want I'm not sure what exactly you are attempting to do.
I have my templated container class that looks like this:
template<
class KeyType,
class ValueType,
class KeyCompareFunctor = AnObnoxiouslyLongSequenceOfCharacters<KeyType>,
class ValueCompareFunctor = AnObnoxiouslyLongSequenceOfCharacters<ValueType>
>
class MyClass
{
[...]
}
Which means that when I instantiate an object of this class, I can do it several different ways:
MyClass<MyKeyType, MyValueType> myObject;
MyClass<MyKeyType, MyValueType, MyCustomKeyCompareFunctor> myObject;
MyClass<MyKeyType, MyValueType, MyCustomKeyCompareFunctor, MyCustomValueCompareFunctor> myObject;
Those are all good. The problem comes when I want to instantiate a MyClass that uses a non-default version of the ValueCompareFunctor argument, but I still want to use the default value of the KeyCompareFunctor argument. Then I have to write this:
MyClass<MyKeyType, MyValueType, AnObnoxiouslyLongSequenceOfCharacters<MyKeyType>, MyCustomValueCompareFunctor> myObject;
It would be much more convenient if I could somehow omit the third argument and just write this:
MyClass<KeyType, ValueType, MyCustomValueCompareFunctor> myObject;
Since the MyCustomValueCompareFunctor works only on objects of type MyValueType and not on objects of type MyKeyType, it seems like the compiler could at least theoretically work out what I meant here.
Is there a way to do this in C++?
In general, both in templates and functions or methods, C++ lets you use default for (and thereby omit) only trailing parameters -- no way out.
I recommend a template or macro to shorten AnObnoxiouslyLongSequenceOfCharacters<MyKeyType> to Foo<MyKeyType> -- not perfect, but better than nothing.
No. The closest you can come is to allow users to specify some sentinel type - like void - meaning "use default value here", and use template metamagic inside your class to typedef the real default if void was given to you. But this probably isn't a good idea from readability point of view.
Boost parameters and Boost graph named parameters are efforts towards naming parameters for template functions/methods. They give the opportunity to provide arguments in whichever order you prefer. Some arguments may be optional, with default values.
The same approach may be applied to template arguments. Instead of having N template arguments + P optional ones, create your class with N+1 template arguments. The last one will hold "named" parameters which can be omitted.
This answer is not complete yet, but i hope it's a good start !
An alternative option is to use Traits classes:
template <class KeyType>
class KeyTraits
{
typedef AnObnoxiouslyLongSequenceOfCharacters<KeyType> Compare;
};
template <class ValueType>
class ValueTraits
{
typedef AnObnoxiouslyLongSequenceOfCharacters<ValueType> Compare;
};
template<class KeyType class ValueType>
class MyClass
{
typedef KeyTraits<KeyType>::Compare KeyCompareFunctor;
typedef ValueTraits<ValueType>::Compare KeyCompareFunctor;
};
Then if you have a type which needs a different comparison function for Key's, then you'd explicitly specialize the KeyTraits type for that case. Here's an example where we change it for int:
template <>
class KeyTraits<int>
{
typedef SpecialCompareForInt Cmopare;
};
There is another option, which uses inheritance and which works like the following. For the last two arguments, it uses a class that inherits virtually from a class that has two member templates, that can be used to generate the needed types. Because the inheritance is virtual, the typedefs it declares are shared among the inheritance as seen below.
template<class KeyType,
class ValueType,
class Pol1 = DefaultArgument,
class Pol2 = DefaultArgument>
class MyClass {
typedef use_policies<Pol1, Pol2> policies;
typedef KeyType key_type;
typedef ValueType value_type;
typedef typename policies::
template apply_key_compare<KeyType>::type
key_compare;
typedef typename policies::
template apply_value_compare<ValueType>::type
value_compare;
};
Now, have a default argument that you use, which has typedefs for the default arguments you want provide. The member templates will be parameterized by the key and value types
struct VirtualRoot {
template<typename KeyType>
struct apply_key_compare {
typedef AnObnoxiouslyLongSequenceOfCharacters<KeyType>
type;
};
template<typename ValueType>
struct apply_value_compare {
typedef AnObnoxiouslyLongSequenceOfCharacters<ValueType>
type;
};
};
struct DefaultArgument : virtual VirtualRoot { };
template<typename T> struct KeyCompareIs : virtual VirtualRoot {
template<typename KeyType>
struct apply_key_compare {
typedef T type;
};
};
template<typename T> struct ValueCompareIs : virtual VirtualRoot {
template<typename ValueType>
struct apply_value_compare {
typedef T type;
};
};
Now, use_policies will derive from all the template arguments. Where a derived class of VirtualRoot hides a member from the base, that member of the derived class is dominant over the member of the base, and will be used, even though the base-class member can be reached by other path in the inheritance tree.
Note that you don't pay for the virtual inheritance, because you never create an object of type use_policies. You only use virtual inheritance to make use of the dominance rule.
template<typename B, int>
struct Inherit : B { };
template<class Pol1, class Pol2>
struct use_policies : Inherit<Pol1, 1>, Inherit<Pol2, 2>
{ };
Because we potentially derive from the same class more than once, we use a class template Inherit: Inheriting the same class directly twice is forbidden. But inheriting it indirectly is allowed. You can now use this all like the following:
MyClass<int, float> m;
MyClass<float, double, ValueCompareIs< less<double> > > m;