I have the following error from Xcode:
Template argument for template template parameter must be a class template or type alias template
However the same exact code works fine in Visual Studio.
template< typename T_NODE, template< typename > class T_ALLOCATOR >
class qt_fixed_pool_general {};
template< template< typename, int > class T_ALLOCATOR, int T_COUNT >
struct static_to_dynamic
{ template< typename T_NODE > using t_allocator = T_ALLOCATOR< T_NODE,T_COUNT >; };
template< typename T_NODE, int T_COUNT >
struct safe_array {};
template< class T_NODE, int T_COUNT >
class qt_fixed_pool_static : public qt_fixed_pool_general<
T_NODE,
static_to_dynamic< safe_array, T_COUNT >::t_allocator >
{};
Any ideas what may be going on?
I am using Xcode 7.2
The problem is that when parsing (not instantiating) the template, the compiler cannot know that t_allocator will be a template and not, say, a static data member. You have to tell it:
template< class T_NODE, int T_COUNT >
class qt_fixed_pool_static : public qt_fixed_pool_general<
T_NODE,
static_to_dynamic< safe_array, T_COUNT >::template t_allocator >
{}; //^^^^^^^^
[Live example]
Note the template keyword added between :: and t_allocator.
The reason why this works in Visual Studio is that VS is not standard-compliant in its template parsing (and has never been): it doesn't do two-phase lookup properly, but instead postpones all name resolution until instantiation time, so it does not trip on errors like this.
Related
I have a class that takes a size type as a parameter in case one doesn't want to use size_t or another hard coded type which would require casting and checking for overflows.
This class also has some methods taking a second template type :
template< typename SizeType = uint32_t >
class BufferReader
{
SizeType m_nPosition;
template< typename T >
T Read();
}
My problem is, what is the syntax to implement this ?
template< typename SizeType, typename T >
T BufferReader< SizeType >::Read()
{
// ...
}
Which gives me an error :
invalid use of incomplete type 'class core::BufferReader<SizeType>'
Or :
template< typename T >
template< typename SizeType >
T BufferReader< SizeType >::Read()
{
// ...
}
Which gives the same error.
Or anything else ?
Thank you !
Your second example is nearly right, you just need to have the template parameters of the class first and those of the function second:
template< typename SizeType >
template< typename T >
T BufferReader< SizeType >::Read()
{
// ...
}
You almost got it. You have to stack the templates as in the declaration: first the class and then the member.
template < typename SizeT >
template < typename T >
T
BufferReader<SizeT>::Read()
{
return T {};
}
Note that the code can be simplified by defining the function right in the class body but I understand that some people will prefer to separate declaration from definition for aesthetic reasons.
I'm attempting variadic template meta programming for the first time and consistently getting a compiler error that I have not been able to track down.
I'm following the "tuple" example on this page (although I'm calling my object an ItemSet)
The ItemSet part compiles just fine:
template<typename...Ts> class ItemSet { };
template<typename item_T, typename ...Ts>
class ItemSet<item_T, Ts...> : public ItemSet<Ts...>
{
public:
ItemSet(item_T t, Ts... item_types) : ItemSet<Ts...>(item_types...), tail(t) { }
protected:
item_T tail;
};
template <typename...M> struct type_holder;
template<typename T, typename ...M>
struct type_holder<0, ItemSet<T, M...>>
{ // ERROR: M parameter pack expects a type template argument.
typedef T type;
};
template <int k, typename T, typename ...M>
struct type_holder<k, ItemSet<T, M...>>
{
typedef typename type_holder<k - 1, ItemSet<M...>>::type type;
};
int main()
{
ItemSet<int, string, string, double> person(0, "Aaron", "Belenky", 29.492);
}
However, in the commented out code, I get the compiler error at the declaration of type_holder.
I've tried a bunch of variations on the same syntax, but always with the same issue.
I'm using Microsoft Visual Studio 2013, which is supposed to have full support for Template programming and Variadic Templates.
Do you understand what the compiler error is, and can you explain it to me?
The immediate problem is that you are defining a specialization of type_holder without a general template. In addition, there is a simple typo (typeholder instead of type_holder). Fixing these two issues makes it compile with other compilers:
template <int, typename T>
struct type_holder;
template <int k, typename T, typename ...M>
struct type_holder<k, ItemSet<T, M...>>
{
typedef typename type_holder<k - 1, ItemSet<M...>>::type type;
};
template<class T, class ...M>
struct type_holder<0, ItemSet<T, M...>>
{
typedef T type;
};
The error emitted by the compilers you used isn't particular helpful. I'd recommend keeping a few C++ compilers around just to test template code with (I'm typically using gcc, clang, and Intel's compiler).
I'm implementing a simple LRU cache in C++11. I pretty much have it covered but there's just one minor problem. Let's say I have the following template class definition:
#ifndef _LRU_STL_H_
#define _LRU_STL_H_
#include <functional>
#include <cassert>
#include <list>
template <typename KeyType, typename ValueType, template<typename...> class Map>
class LRU {
public:
typedef Map<KeyType, std::pair<ValueType, typename std::list<KeyType>::iterator>> KeyToValueType;
LRU(const std::function<ValueType(const KeyType&)> &Function, size_t Capacity)
: _Function(Function), _Capacity(Capacity) {
assert(_Capacity != 0);
}
...
private:
...
std::function<ValueType(const KeyType&)> _Function;
const size_t _Capacity;
KeyToValueType _KeyToValue;
};
#endif
At KeyToValue type I get the following compilation error with MSVC2013: Error 1 error C2976: 'std::map' : too few template arguments c:\x\visual studio 2013\projects\caching\lru_stl\lru_stl.h 17 1 LRU_STL
The 17th line is:
typedef Map<KeyType, std::pair<ValueType, typename std::list<KeyType>::iterator>> KeyToValueType;
Seems like the template deduction fails. It may be a very simple problem but I just couldn't find it yet. For completeness here's an example:
std::function<std::string(std::string)> functionToCache = [](std::string & str) {
std::string reverse;
reverse.reserve(str.size());
std::copy(str.begin(), str.end(), reverse);
return reverse;
};
LRU<std::string, std::string, std::map> LRU(functionToCache, 5);
std::string Hello_World = LRU("Hello World");
assert(Hello_World == "dlroW olleH");
The error is already provided. Done mentioned fixes. Still the same error occurs: std::map too few template arguments.
Just for completeness if I remove everything and create a TEST class:
template <typename A, typename B, template <typename ...> class Map>
class TEST {
typename Map<A, std::pair<B, typename std::list<A>::iterator>> CMAP;
public:
TEST(void) { }
};
Trying to instantiate the class results in the exact same error message.
#Update:
VC++ Compiler seems to be unable to process default template parameters in this particular scenario. To solve the issue I had to add all four template parameters to the typedef and so the definition became like:
template <typename K, typename V, template <typename...> class Map>
class Test {
typedef Map<K, std::pair<V, typename std::list<K>::iterator>, std::less<K>, std::allocator<std::pair<const K, typename std::list<K>::iterator>>> MapType;
};
That would be all to this issue. Thanks for all who tried to help and for that professional gentleman with: 'I don't have even the slightest idea about this question, Let's DOWNVOTE it!!!'. You really are amazing! Wish you the best man....
Your missed two points.
First, template template parameter should be like this:
template < parameter-list > class name
So your
template<typename...> Map
should be
template<typename...> class Map
Second, you should use typename with dependent names. In your code, std::list<Key>::iterator is a dependent name (depending on Key). So, you should use typename std::list<Key>::iterator instead.
Here's my corrected test code.
#include <list>
#include <map>
template <typename Key, typename Value,
template <typename...> class Map>
class Test
{
public:
typedef Map<
Key,
std::pair<Value, typename std::list<Key>::iterator>
> KeyToValueType;
};
int main()
{
Test<int, char, std::map>::KeyToValueType asdf;
}
It worked both in g++ 4.9.1 and in clang++ 3.5.
It seems to be due to VC++'s foolishness. It may work if you give the full template parameter to std::map, including comparer and allocator, since VC++ seems not to be able to process default template parameter in this case.
I have rather simple, I imagine, question about CRTP, but I cannot seem to find an answer to it. Probably, because it is so simple, no one thought of asking it. I am new to the concept, so, please don't laugh too hard ;).
Here is the code (it's sort of an attempt to do something similar to STL containers):
template< typename tT >
struct TBase
{
typedef tT T;
};
template< typename tTBase >
struct TTraitsBase
{
typedef typename tTBase::T T;
};
template< typename tTHelpee, typename tTTraits >
struct THelper
{
typedef typename tTTraits::T T;
typedef typename tTHelpee::T Th; /* This generates a compiler error:
'T' not being a member of TDerived<tT> */
T Foo( void )
{
return static_cast< tTHelpee* > ( this )->mVal;
}
};
template< typename tT >
struct TDerived : TBase< tT > , THelper< TDerived< tT > , TTraitsBase< TBase< tT > > >
{
using TBase< tT >::T;
T mVal;
};
int main()
{
TDerived< int >::T lTmp = -1;
TDerived< int > lObj;
lObj.mVal = -1;
std::cout << lObj.Foo() << std::endl;
return 0;
}
Everything compiles if I comment the offending typedef typename _THelpee::T Th;. And that what confuses me: if compiler does not like typedef typename _THelpee::T Th;, why does it let through static_cast< _THelpee* > ( this )->mVal? I assume, it has something to do with not being able to instantiate THelper when instantiating TDerived, but no clear understanding. Can someone, please, give a brief explanation and/or some references on what is happening here? Thank you.
EDIT: removed '_T' prefix.
Implicitly instantiating a class does not instantiate its member function definitions. Each member of a class template is instantiated only when used (unless you use explicit instantiation).
The first thing you implicitly instantiate is TDerived<int>, on the first line of main. To instantiate that, the compiler looks up the TDerived template, sees that there are a couple of dependent base classes, so tries to instantiate those. TBase<int> instantiates with no problem. But on trying to instantiate THelper< TDerived<int>, TTraitsBase< TBase<int> > >, there's an attempt to get a member TDerived<int>::T, but TDerived<int> is still an incomplete type.
Instantiating THelper< ... > also notes that there is a member function int Foo(), but does not evaluate the semantics of its definition.
By the time you call lObj.Foo() from main, which instantiates that int THelper< ... >::Foo(), TDerived<int> is a complete type, so there's no problem there.
There are couple of problem with the code posted. Since, I couldn't make out the intention, I will list what I found erroneous.
(1) Using an incomplete type:
template< typename _T >
struct TDerived : TBase< _T > , THelper< TDerived< _T > , TTraitsBase< TBase< _T > > >
^^^^^^^^^^^^^^ it's incomplete
IMO when you are defining the body of TDerived<_T>, you should not use the same as a parameter to anything.
(2) Improper type definition.
using TBase< _T >::T;
should be,
typedef typename TBase< _T >::T T;
I'd say you have a circular dependency in your CRTP (as one would have, by its very nature), but that means that the base template class isn't allowed to use any of its parameter class, because that very parameter class isn't defined yet - it's still an incomplete type at the time where Base<T> is instantiated.
So, this is OK:
template <typename T> struct Base
{
T * impl; // incomplete type is OK
};
class Foo : public Base<Foo> { /* ... */ };
But this isn't:
template <typename T> struct Base
{
T x; // need to know T, but T depends on Base<T>!
};
Continuing my journey into the world of variadic templates, I encountered another problem.
Assuming the following template class:
template < typename T >
struct foo
{
//default implementation
};
it is possible to partially specialize it for variadic template instantiations like this:
template < template < typename ... > class T, typename ...Args >
struct foo< T< Args... > >
{
//specialized implementation
};
With this, foo< int > will correspond to the default implementation and foo< std::tuple< int, char > > to the specialized implementation.
However, things become more complicated when using several template parameters. For example, if we have the following template class
template < typename T, typename U >
struct bar {};
and we want to partially specialize it as we did for foo, we cannot do
template < template < typename ... > class T, typename ...TArgs,
template < typename ... > class U, typename ...UArgs >
struct bar< T< TArgs... >, U< UArgs... > > {};
//This would correspond to the specialized version with
//T=std::tuple,
//TArgs=int,char
//U=std::tuple,
//UArgs=float
bar< std::tuple< int, char >, std::tuple< float > > b;
Indeed, if I am correct, we can only have one template parameter pack and it must be positioned at the end of the parameter list. I understand why this is mandatory in template declarations, but for certain partial template specialization (like the example above), this should not be an issue.
Is it possible to achieve partial template specialization with multiple template parameter packs?
Edit: Now I feel silly...the code I gave above compiles perfectly (at least with gcc 4.5). The compile error I had was not because of multiple parameter packs, but because of their use as member functions parameters. In the partial specialization of bar, I tried to define a member function that takes both TArgs and UArgs parameters:
template < template < typename ... > class T, typename ...TArgs,
template < typename ... > class U, typename ...UArgs >
struct bar< T< TArgs... >, U< UArgs... > >
{
void method( TArgs... targs, UArgs... uargs ) //compile error here
{
}
};
On the member function declaration, gcc gives me the error
parameters packs must be at the end of the parameter list.
As far as I can tell, the compiler should be able to define the correct member function for a given template instantiation, e.g. bar< std::tuple< int, char >, std::tuple< float > > should contain a member function void method( int, char, float ). Am I doing something wrong? Or am I trying to do something that is not possible? If so, is there a good reason why this is not possible?
Probably this answer won't clear your question directly,
but the following code compiled on ideone(gcc-4.5.1) when I tested.
#include <cstdio>
#include <tuple>
template< class, class > struct S {
S() { puts("primary"); }
};
template<
template< class... > class T, class...TArgs
, template< class... > class U, class...UArgs
>
struct S< T< TArgs... >, U< UArgs... > > {
S() { puts("specialized"); }
};
int main()
{
S< int, int > p; // "primary"
S< std::tuple< int, char >, std::tuple< float > > s; // "specialised"
}
I'm not sure this code is strictly conformant, but
as far as I read N3225 14.5.3, I couldn't find the statement which mentions
that template parameter pack has to be the last template parameter.
Edit:
I reread N3225 and found the following statements:
8.3.5/4 If the parameter-declaration-clause
terminates with an ellipsis or a
function parameter pack (14.5.3), the
number of arguments shall be equal to
or greater than the number of
parameters that do not have a default
argument and are not function
parameter packs.
14.8.2.5/10 [Note: A function parameter pack can only occur at the
end of a
parameter-declarationlist(8.3.5). -end
note]
So, as you mentioned, function parameter pack has to be the last parameter
unfortunately.
A non-template member function of a class template is an ordinary function
for that class when it is instantiated(fully specialized).
So I wish that the code in this question can be compiled logically, as a
special case.