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;
Related
I want to use 'MyType' from the base class in the 'DoesBlah' test below.
#include <gtest/gtest.h>
template <typename T>
struct MemberVariable
{
T m_t;
};
struct Base : public ::testing::Test
{
template <typename MemberType>
using MyType = MemberVariable<MemberType>;
};
template <typename DerivedType>
struct Derived : public Base
{
};
typedef ::testing::Types<int, char> MyTypes;
TYPED_TEST_CASE(Derived, MyTypes);
TYPED_TEST(Derived, DoesBlah)
{
MyType<TypeParam> test;
test.m_t = (TypeParam)1;
ASSERT_EQ(test.m_t, 1);
}
However, I get the following compilation error:
gti/specific/level/Test.t.cpp: In member function 'virtual void Derived_DoesBlah_Test<gtest_TypeParam_>::TestBody()':
gti/specific/level/Test.t.cpp:25:5: error: 'MyType' was not declared in this scope
MyType<TypeParam> test;
I tried using TestFixture::MyType, typename TestFixture::MyType, but both did not work.
How can I get Derived to recognize that there's something called 'MyType'?
With some simplifications, the macro TYPED_TEST(Derived, DoesBlah) expands to something like:
template <typename TypeParam>
class Derived_DoesBlah_Test : public Derived<TypeParam>
{
private:
typedef Derived<TypeParam> TestFixture;
virtual void TestBody();
};
template <typename TypeParam>
void Derived_DoesBlah_Test<TypeParam>::TestBody()
So the {} block that follows is the function definition for a member of a template class which derives from Derived<TypeParam>. The typedef for TestFixture is available, but it depends on the template parameter TypeParam, so it is considered a dependent type. What's more, you want to access a template member of that dependent type. So you need both the typename and template keywords:
{
typename TestFixture::template MyType<TypeParam> test;
test.m_t = (TypeParam)1;
ASSERT_EQ(test.m_t, 1);
}
For more about dependent types and using the typename and template keywords in declarations and expressions, see this SO question.
I want to use a pointer to a class member as a template parameter as in:
template <class Class, class Result, Result Class::*Member>
struct MyStruct {
// ...
};
Using this struct like MyStruct<SomeClass, SomeResult, &SomeClass::value> variable works just fine, but I don't like that I have to specify SomeClass and SomeResult.
I would like to use MyStruct<&SomeClass::value> variable if that is possible, but without losing the ability to pass any class and have any result type.
I tried the following, but the syntax is illegal:
template <class Class, class Result>
template <Result Class::*Member>
struct MyStruct {
// ...
};
error: too many template-parameter-lists
I tried using a helper function (that does actually work in Clang but is refused by GCC):
template <class Class, class Result>
static constexpr auto makeMyStruct(Result Class::*member) ->
MyStruct<Class, Result, member> {
// ...
}
error: use of parameter `member' outside function body
error: template argument 3 is invalid
Is it possible to have a simple MyStruct<&SomeClass::value>, and if so, how?
Related question that did not solve my question:
Pointer to class member as template parameter
C++0x error with constexpr and returning template function
In c++17, with the addition of auto in template arguments (P0127), I think you can now do:
template<auto value>
struct MyStruct {};
template<typename Class, typename Result, Result Class::* value>
struct MyStruct<value> {
// add members using Class, Result, and value here
using containing_type = Class;
};
typename MyStruct<&Something::theotherthing>::containing_type x = Something();
An answer to my question was proposed in this paper for the next upcoming C++ standard:
https://isocpp.org/files/papers/n3601.html
This syntax was proposed:
template<using typename T, T t>
struct some_struct { /* ... */ };
some_struct<&A::f> x;
The need for a new syntactical construct indicates that you cannot do that by now.
I hope n3601 will be accepted. :-)
This could be a solution in C++11:
You can define the following generic type traits:
template<class T>
struct remove_member_pointer {
typedef T type;
};
template<class Parent, class T>
struct remove_member_pointer<T Parent::*> {
typedef T type;
};
template<class T>
struct baseof_member_pointer {
typedef T type;
};
template<class Parent, class T>
struct baseof_member_pointer<T Parent::*> {
typedef Parent type;
};
Now you can define an additional, 4-line wrapper macro for every struct:
template<class Class, class Result, Result Class::*Member>
struct _MyStruct {
// ...
};
#define MyStruct(MemberPtr) \
_MyStruct<baseof_member_pointer<decltype(MemberPtr)>::type, \
remove_member_pointer<decltype(MemberPtr)>::type, \
MemberPtr>
... and use it in the following way:
MyStruct(&SomeClass::value) myStruct; // <-- object of type MyStruct<&SomeClass:value>
I use this as an intermediate solution, until we switch to C++17.
Make your result class a child of your template class. assuming the pointer member is an object of your result class in public or whatever, you can access any objects by doing something like this
template <stuff for this class> :: public result
{
blah
}
I want to use a pointer to a class member as a template parameter as in:
template <class Class, class Result, Result Class::*Member>
struct MyStruct {
// ...
};
Using this struct like MyStruct<SomeClass, SomeResult, &SomeClass::value> variable works just fine, but I don't like that I have to specify SomeClass and SomeResult.
I would like to use MyStruct<&SomeClass::value> variable if that is possible, but without losing the ability to pass any class and have any result type.
I tried the following, but the syntax is illegal:
template <class Class, class Result>
template <Result Class::*Member>
struct MyStruct {
// ...
};
error: too many template-parameter-lists
I tried using a helper function (that does actually work in Clang but is refused by GCC):
template <class Class, class Result>
static constexpr auto makeMyStruct(Result Class::*member) ->
MyStruct<Class, Result, member> {
// ...
}
error: use of parameter `member' outside function body
error: template argument 3 is invalid
Is it possible to have a simple MyStruct<&SomeClass::value>, and if so, how?
Related question that did not solve my question:
Pointer to class member as template parameter
C++0x error with constexpr and returning template function
In c++17, with the addition of auto in template arguments (P0127), I think you can now do:
template<auto value>
struct MyStruct {};
template<typename Class, typename Result, Result Class::* value>
struct MyStruct<value> {
// add members using Class, Result, and value here
using containing_type = Class;
};
typename MyStruct<&Something::theotherthing>::containing_type x = Something();
An answer to my question was proposed in this paper for the next upcoming C++ standard:
https://isocpp.org/files/papers/n3601.html
This syntax was proposed:
template<using typename T, T t>
struct some_struct { /* ... */ };
some_struct<&A::f> x;
The need for a new syntactical construct indicates that you cannot do that by now.
I hope n3601 will be accepted. :-)
This could be a solution in C++11:
You can define the following generic type traits:
template<class T>
struct remove_member_pointer {
typedef T type;
};
template<class Parent, class T>
struct remove_member_pointer<T Parent::*> {
typedef T type;
};
template<class T>
struct baseof_member_pointer {
typedef T type;
};
template<class Parent, class T>
struct baseof_member_pointer<T Parent::*> {
typedef Parent type;
};
Now you can define an additional, 4-line wrapper macro for every struct:
template<class Class, class Result, Result Class::*Member>
struct _MyStruct {
// ...
};
#define MyStruct(MemberPtr) \
_MyStruct<baseof_member_pointer<decltype(MemberPtr)>::type, \
remove_member_pointer<decltype(MemberPtr)>::type, \
MemberPtr>
... and use it in the following way:
MyStruct(&SomeClass::value) myStruct; // <-- object of type MyStruct<&SomeClass:value>
I use this as an intermediate solution, until we switch to C++17.
Make your result class a child of your template class. assuming the pointer member is an object of your result class in public or whatever, you can access any objects by doing something like this
template <stuff for this class> :: public result
{
blah
}
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;
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:
...
};