Considering the following couple of classes:
template <typename T1, typename T2>
class A{
public:
// ...
};
template<typename _T>
struct alias { typedef A<int,_T> intA; };
class B{
public:
// ...
template <typename _T> B& operator=(const typename alias<_T>::intA& _arg) { };
};
When I try to assign an object of class A<int,int> to an object of class B, I get the following compilation error:
template argument deduction/substitution failed: couldn't deduce template parameter ‘_T’
Is there an alternative way to use something of a typedef as the input argument to B::operator=()??
templated using might fix the issue
template <typename T1, typename T2>
class A{
public:
// ...
};
template<typename _T>
using alias = A<int,_T>;
class B{
public:
// ...
template <typename _T> B& operator=(const alias<_T>& ) { return *this; };
};
void f()
{
B b;
A<int, int> a;
b = a;
}
The problem is that intA is a dependant name. Templates cannot be deduced from dependant names. See for example: Dependent Types: Template argument deduction failed.
You are also missing the typename keyword.
You can either explicitly specify the type for the operator:
template <typename T1, typename T2>
struct A{ };
template<typename _T>
struct alias { typedef A<int,_T> intA; };
struct B
{
template <typename T> B& operator=(const typename alias<T>::intA& _arg) { };
};
int main()
{
A<int,int> a;
B b;
b.operator=<int>(a);
return 0;
}
or you can have a specific, non-dependant-name parameter using a templated alias (with or without a function):
template <typename T1, typename T2>
struct A{ };
template<class T>
using alias_int = A<int, T>;
struct alias
{
template<class T>
using intA = A<int, T>;
};
struct B
{
template <typename T> B& operator=(const alias_int<T>& _arg) { };
};
struct C
{
template <typename T> C& operator=(const alias::intA<T>& _arg) { };
};
int main()
{
A<int,int> a;
B b;
C c;
b = a;
c = a;
return 0;
}
I'm getting a different error (using g++ 5.4):
need ‘typename’ before ‘alias<_T>::intA’ because ‘alias<_T>’ is a dependent scope
and true enough the following compiles for me:
template <typename T1, typename T2>
class A{
public:
// ...
};
template<typename _T>
struct alias { typedef A<int,_T> intA; };
class B{
public:
// ...
template <typename _T> B& operator=(const typename alias<_T>::intA& _arg) { };
};
I think the reason is that alias<_T>::intA isn't an actual type but a templated typename.
Related
I got three template classes (Code in C++ Shell) and an alias template using AType = A<T1,T2> defined in A. I would like to use the alias across the files where objects of A are being used.
So in B instead of writing:
C<A<T1,T2>> c_object;
I'd rather like to be able to write something like:
C<typename AType> c_object;
using the alias declared in A.
// A.h
template<typename T1, typename T2>
class A{
A();
};
template<typename T1, typename T2>
using AType = A<T1,T2>;
// C.h
template<typename H>
// H = A<T1,T2>
class C{
C();
};
// B.h
#include "A.h"
template<typename T1, typename T2>
class B{
B();
// const C<A<T1,T2>>& GetC() const;
const C<typename AType>& GetC() const;
private:
C<typename AType> c_object;
};
Note the relations of the template parameters.
If B would only have one template parameter G like:
template<typename G>
class B{};
I could just do:
C<typename G::AType> c_object;
But since B actually has two, I can't figure out how that would work out. Or is entire problem usually solved in a different way?
You should instead add a using to B for your C type:
#include "A.h"
template<class T1, class T2>
struct B{
using C_type = A<T1, T2>;
B();
// const C_type& GetC() const;
const C_type& GetC() const;
private:
C_type c_object;
};
Or could inject A into the template arguments for B, which would let the caller optionally change it:
#include "A.h"
template<class T1, class T2, template<class, class> class C_T = A<T1, T2>>
struct B{
B();
// const C_T& GetC() const;
const C_T& GetC() const;
private:
C_T c_object;
}
You misunderstand what template aliases are for. They simply make referring to some other template easier; they don't implicitly bind template arguments to be passed on (T1 and T2 don't get implicitly passed to A in your OP; the template arguments to A must be specified).
You could simplify writing a C type templated for A using a template alias:
template<class T1, class T2>
using C_A = C<A<T1, T2>>;
And then you could use C_A<T1, T2> in B. This may be more flexible if you need a C templated on A in more than one location. However, what I wrote above may be preferable; this was only for demonstrated purposes.
The problem is that AType isn't a type; it's a template template type.
Your code compile if you write C as follows
template <template <typename...> class>
class C
{ C(); };
and pass AType in this way
template <typename T1, typename T2>
class B
{
B();
const C<AType>& GetC() const;
private:
C<AType> c_object;
};
but I don't understand what do you want to do with C and AType
-- EDIT --
Klaus say
In your posted code you write C<AType> c_objectwhich is invalid as using AType = A;`. I can't see the place where you put any type to aliased template AType. So your posted code makes no sense as T1 and T2 are unused.
My answer: I suppose that my posted code "makes no sense as T1 and T2 are unused", because I didn't understand the sense of the original code.
But you say my code "is invalid".
The following is my code that use C<AType> c_objectwhich and using AType = A<T1,T2>;. Please, say to me where is invalid and which error you get compiling it.
template <typename, typename>
class A { A(); };
template <typename T1, typename T2>
using AType = A<T1,T2>;
template <template <typename...> class>
class C { C (); };
template <typename, typename>
class B
{
B();
const C<AType> & GetC () const;
private:
C<AType> c_object;
};
int main()
{ }
template <typename, typename>
class A { A(); };
template <typename T1, typename T2>
using AType = A<T1,T2>;
template <template <typename...> class>
class C { C (); };
template <typename, typename>
class B
{
B();
const C<AType> & GetC () const;
private:
C<AType> c_object;
};
int main()
{ }
#include <iostream>
template <typename T1, typename T2>
class B{
public:
void update(){ std::cerr<<__PRETTY_FUNCTION__<<std::endl; }
void func1(){ std::cerr<<__PRETTY_FUNCTION__<<std::endl; }
void func2(){ std::cerr<<__PRETTY_FUNCTION__<<std::endl; }
};
template <typename T1>
class B<T1, int>{
public:
void update(){ std::cerr<<__PRETTY_FUNCTION__<<"(specialization)"<<std::endl;}
};
int main(){
B<int, double> b1;
b1.update();
b1.func1();
B<int, int> b2;
b2.update();
//b2.func1();//there's no function 'func1' in B<int,int>
}
I want to specialize update function for specific template parameter(data type).
So I tried to specialize template class B but it seems that I have to implement whole member functions again.
Because other members are exactly same between specializations, reimplementing whole members look cumbersome.
Is there any workaround for this case?
Tag-dispatch the call to update:
template <typename> struct tag {};
template <typename T1, typename T2>
class B
{
public:
void update()
{
return update(tag<B>());
}
private:
template <typename U1>
void update(tag<B<U1, int> >)
{
// specialization
}
template <typename U1, typename U2>
void update(tag<B<U1, U2> >)
{
// normal
}
};
DEMO
I have five classes, declared so:
template <typename T>
class A {
void fn(X);
};
template <typename T>
class B {};
class C {};
class D {};
class X {};
and I have two instances declared so:
A<B<C>> abc;
A<B<D>> abd;
How can I templatize fn so that one must call abc.fn() with an object of type C and abd.fn() with an object of type D?
You can do a partial specialization of your class like this:
template <typename T> class A;
template <typename T> class B {};
template <typename T>
class A<B<T> > {
public:
void fn(T) { }
};
class C {};
class D {};
int main(int,char**)
{
A<B<C>> abc;
A<B<D>> abd;
abc.fn(C());
abd.fn(D());
return 0;
}
If you want it to work for any template, and not just B, you can partially specialize class A like this:
template <typename T,template <typename> class U>
class A<U<T> > {
public:
void fn(T) { }
};
This is not going to be too pretty.
template <typename T>
class B {public: typedef T type;};
template <typename T>
class A {
void fn(typename T::type X);
//void fn(...){} // would prevent an error if T does not have type.
};
Basically you save the type in a typedef and then use that in A. This would error out of course if B does the T of A does not have T::type.
I have a class that derives from a templated class:
template <typename A,typename B>
class TemplatedClass {
};
class Hello : public TemplatedClass<int,float>
{
};
Now, I want to make a templated class that will infer the types int,float from Hello.
I thought I could do something like this, but it doesn't work:
template <template <typename A,typename B> class C>
class Check
{
void Foo(A,B,C)
{
// A is int .. B is float .. C is Hello
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Check<Hello> a;
}
How can i do this ?
Edit:
I want to pass the class Hello and have the template infer the types used by its subclass TemplatedClass .
So, when I create a class Check<Hello> it will get the types int and float
I can't really change the TemplatedClass to include typedefs (it's from an an external .lib)
Edit:
I've changed the template to use Class , I get this error though:
error C3200: 'Hello' : invalid template argument for template parameter 'C', expected a class template
First, change that typename to class, §14.1 [temp.param] p1:
type-parameter:
class identifieropt
class identifieropt = type-id
typename identifieropt
typename identifieropt = type-id
template <template-parameter-list > class identifieropt
template <template-parameter-list > class identifieropt = id-expression
Next, make a partial specialization:
template<class T>
class Check;
template< // not 'typename' vvvvv
template<typename,typename> class C,
typename A, typename B
>
struct Check<C<A,B> >{
// ...
};
Though, you still can't pass just Hello to the template, because even though Hello derives from TemplatedClass, type conversion is not allowed for template parameters:
Check<Hello> c; // nope, 'Hello' is not a template
You could add the following typedef to the Hello class:
class Hello
: TemplatedClass<int,float>
{
public:
typedef TemplatedClass<int,float> base_type;
};
And do:
Check c; // OK
But then the C parameter in Check will be template TemplatedClass, not Hello. Sadly, there's no way to achieve that directly. One solution is to pass the derived type either as an extra template parameter or just pass the derived type as the only parameter and do the type extraction internally:
template<class T>
class CheckInternal;
template<
template<typename,typename> class C,
typename A, typename B
>
class CheckInternal<C<A,B> >{
public:
typedef A type_A;
typedef B type_B;
};
template<class T>
class Check{
typedef typename T::base_type T_base_type;
typedef typename CheckInternal<T_base_type>::type_A type_A;
typedef typename CheckInternal<T_base_type>::type_B type_B;
void foo(type_A a, type_B b){
// ...
}
};
// usage:
C<Hello> c; // OK!
You could do something like this:
template <template <typename A,typename B> typename C>
class Check
{
template<typename A, typename B>
void Foo(A a, B b) {
// C<A,B> would reconstruct the template type
}
}
// use:
Check<Hello> a;
a.Foo(true,1.f);
or alternatively, this (it's not exactly clear what your intent is):
template <typename A,typename B>
class TemplatedClass {
typedef A TypeA;
typedef B TypeB;
};
template <typename C>
class Check
{
void Foo(typename C::TypeA& a, typename C::TypeB&) {}
}
// use:
Check<Hello<int,float> > a;
a.Foo(1,1.f);
Try something like:
template <typename A,typename B>
class TemplatedClass {
public:
typedef A firstType;
typedef B secondType;
};
class Hello : public TemplatedClass<int,float>
{
public:
typedef firstType Type1;
typedef secondType Type2;
};
template <typename C>
class Check
{
typedef typename C::Type1 A;
typedef typename C::Type2 B;
void Foo(A,B,C)
{
// A is int .. B is float .. C is Hello
}
};
I think you can do it by creating a templated class for Hello and then typedefing a specialization of it. Something like:
template <typename A, typename B>
class HelloBase : public TemplatedClass<A, B>
{
public:
typedef A Type1;
typedef B Type2;
};
typedef HelloBase<int, float> Hello;
template <typename C>
class Check
{
typedef typename C::Type1 A;
typedef typename C::Type2 B;
void Foo(A,B,C)
{
// A is int .. B is float .. C is Hello
}
};
...
Check<Hello> a;
So TemplatedClass doesn't need to change, and you can put everything you were going to put in Hello into HelloBase (using the templating as a tool for simply carrying around types).
What you want is impossible in the general case- what if Hello derived from TemplatedClass twice?
It is, however, fairly simple to do, even non-intrusively, under C++0x.
template<typename A, typename B> struct retval {
typedef A first;
typedef B second;
};
template<typename one, typename two> one first(const TemplatedClass<one, two>& ref);
template<typename one, typename two> two second(const TemplatedClass<one, two>& ref);
template<typename T> class Check {
typedef decltype(first(*static_cast<T*>(nullptr))) first;
typedef decltype(second(*static_cast<T*>(nullptr))) second;
};
In C++03 then you can still get the parameters inside the method, but can't access them outside, unless you insert special typedefs.
I have a method and two classes defined like this:
template<template<class X> class T>
void doSomething()
{
T<int> x;
}
template <class T>
class ClassWithOneArg
{
T t;
};
template <class T1, class T2>
class ClassWithTwoArgs
{
T1 t1;
T2 t2;
};
I can now
doSomething<ClassWithOneArg>();
but I cannot
doSomething<ClassWithTwoArgs>();
However, I'd like to pass ClassWithTwoArgs to doSomething, where T2 = double.
The only method I found is to create
template <class T1>
class ClassWithTwoArgs_Child
: public ClassWithTwoArgs<T1, double>
{
};
and then
doSomething<ClassWithTwoArgs_Child>();
This works, but in my concrete case all classes require a constructor argument and thus I have to create a constructor with this argument also in the _Child-class and pass it to the base which I really want to avoid.
Do you have an idea how to do that?
Thanks a lot!
Indirection is a solution. Instead of a template template parameter you pass a "meta function" -- a function that maps one type to another in form of a struct with a nested class template:
struct mf1 {
template<class Arg1>
struct eval {
typedef ClassTemplateWithOneArg<Arg1> type;
};
};
template<class Arg2>
struct mf2 {
template<class Arg1>
struct eval {
typedef ClassTemplateWithTwoArgs<Arg1,Arg2> type;
};
};
template<class MetaFunc>
void do_something()
{
typedef typename MetaFunc::template eval<int>::type clazztype;
clazztype x;
}
void foo() {
do_something<mf1>();
do_something<mf2<double> >();
}
In C++0x this could be reduced to a "template typedef":
template<class Arg1>
using NewClassTemplate = ClassTemplateWithTwoArgs<Arg1,double>;
which allows you to pass NewClassTemplate as a template template argument which also accepts only one template parameter.
There is no generic solution. Your best bet is
template<class T>
void doSomething()
{
T x;
}
template <class T>
class ClassWithOneArg
{
T t;
};
template <class T1, class T2 = double>
class ClassWithTwoArgs
{
T1 t1;
T2 t2;
};
int main(){
doSomething<ClassWithOneArg<int>>();
doSomething<ClassWithTwoArgs<int, double> >();
}
It seems that what you are after is similar to the rebinding of allocators (given an allocator, containers need to be able to produce an allocator for a different type - e.g std::list<int> might need a allocator<list_node<int> > from allocator<int>.
However, the class templates would have to be modified for this.
template<class T>
void doSomething(const T&)
{
typename T::template rebind_1st<int>::type x;
}
template <class T>
class ClassWithOneArg
{
T t;
public:
template <class U>
struct rebind_1st { typedef ClassWithOneArg<U> type; };
};
template <class T1, class T2>
class ClassWithTwoArgs
{
T1 t1;
T2 t2;
public:
template <class U>
struct rebind_1st { typedef ClassWithTwoArgs<U, T2> type; };
};
int main()
{
doSomething(ClassWithOneArg<char>());
doSomething(ClassWithTwoArgs<char, double>() );
}
Assuming you want declare template instantiations of the same class with a different type for the first template parameter, it appears a version of visitor's code is possible that doesn't require modifying original classes.
template <class T, class NewFirstArg>
struct rebind_1st;
template <template <class> class T, class Arg1, class NewFirstArg>
struct rebind_1st<T<Arg1>, NewFirstArg>
{
typedef T<NewFirstArg> type;
};
template <template <class, class> class T, class Arg1, class Arg2, class NewFirstArg>
struct rebind_1st<T<Arg1, Arg2>, NewFirstArg>
{
typedef T<NewFirstArg, Arg2> type;
};
template <class T>
void foo()
{
typename rebind_1st<T, int>::type x;
(void)x;
}
template <class T>
struct One{};
template <class T1, class T2>
struct Two{};
int main()
{
foo<One<char> >();
foo<Two<char, double> >();
}
This works with MSVC:
template<class T>
void doSomething()
{
T x;
}
// class definitions omitted...
void test() {
doSomething<ClassWithOneArg<int> >();
doSomething<ClassWIthTwoArgs<int, double> >();
}
I do not fully understand why you want to define the first parameter of your template template parameter to be int inside of doSomething. Looks like a "template smell" to me, since doSomething has to know a lot about its template template parameter.
Wouldn't it be cleaner to call doSomething the way i proposed? (But obviously i don't know the context of your calls).