I have this template, which ends up having a really long, awkward name:
template <class A>
struct foo {
template <class B>
struct bar {
template <class L>
struct baz {
template <int N>
class MyTemplate {
public:
MyTemplate(A a, B b);
};
};
};
};
The nested structure makes sense in the implementation (hidden from this toy example), so I don't want to change it. Now every time I want to use the template, I need to write foo<int>::bar<float>::baz<float>::MyTemplate<5>. I know I can do:
template <class A, class B, class L, int N>
class MyTemplate_Shortcut : public foo<A>::bar<B>::baz<L>::MyTemplate<N> {
// ...
};
The problem is that the constructor of MyTemplate is now hidden. Unfortunately, different instantiations may have different constructor signatures, so it is impossible to write one constructor to call them all. I could also do this:
template <class A, class B, class L, int N>
struct MyTemplate_Shortcut { {
typedef foo<A>::bar<B>::baz<L>::MyTemplate<N> MyTemplate;
};
And now I can do MyTemplate_Shortcut<int, float, float, 5>::MyTemplate, which is better but not quite perfect. Is there any trick, such as CRTP or similar to inject a constructor of MyTemplate into MyTemplate_Shortcut? I know that in C++11, there is a simple solution with template alias:
template <class A, class B, class L, int N> using MyTemplate_Shortcut =
foo<A>::bar<B>::baz<L>::MyTemplate<N>;
Note that I'm not particularly sure about the syntax as I have not used it before. Is there a non-C++11 way to do this?
I'd propose the following solution, which uses a typedef for shortcutting the nested template classes.
...
template <class A, class B, class L, int N>
struct MyTemplate_Shortcut {
typedef class foo<A>::bar<B>::baz<L>::MyTemplate<N> Type;
};
MyTemplate_Shortcut<int, long, float, 5>::Type instance(5, 17);
Related
Consider the code below:
template <typename T>
class A{
...
}
template <class U>
class B{
...
}
int main {
B<A<int>> a;
...
}
How can I get the template parameter of A (int in this case) inside B, if A<int> is the template parameter for B?
I could parametrize B as follows, but I feel like I am sending an unnecessary piece of information.
template <class AA, typename T>
class B { ... }
The reason I do not simply use template <typename T> for class B is that I have a pointer to class A inside B, and I want to use the template parameter class AA to see if that pointer is const or not, hence have the correct type for the member pointer in B.
There are several ways, depending of that you might change:
Quick way, specialize B
template <class> class B;
template <class T>
class B<A<T>>
{
// Use directly T
//...
};
Add info in A directly (as std containers do with value_type)
template <typename T>
struct A
{
using my_type = T;
};
// Then in `B<U>`, use `typename U::my_type`
Use external traits to extract information from A (as std::iterator_traits) (that also allows to handle built-in types):
template <typename T>
struct ATrait;
template <typename T>
struct ATrait<A<T>>
{
using my_type = T;
};
// Possibly a generic one
template <template <typename> class C, typename T>
struct ATrait<C<T>>
{
using my_type = T;
};
// Then in `B<U>`, use `typename ATrait<U>::my_type`
I think the following does what you want:
#include<type_traits>
template<class>
class A{};
template<class>
struct get_inner;
template<template<class> class TT, class T>
struct get_inner<TT<T>> {
using outer = TT<T>;
using inner = T;
};
template<class TT>
struct B {
using A = TT;
using inner = typename get_inner<std::decay_t<A>>::inner;
};
int main(int argc, char *argv[])
{
static_assert(std::is_const_v<typename B<const A<int>>::A>);
static_assert(!std::is_const_v<typename B<A<int>>::A>);
}
Note the std::decay_t, it wouldn't work with the const parameter directly (hence we cannot just specialize B in this way). Maybe decay_t is a bit strong but it works^^
Try this
template <typename X> class B;
template <template <typename> class XX, typename T>
class B<XX<T>>
{
// your implementation
};
B<A<int>> a;
If I have a template class A, like this
template <int n>
class A{
/* some code */
};
Is it possible to have a template class B, that takes a reference or pointer to an A as parameter without having the int n as template parameter in B.
The following code would work:
template <int n, A<n> &a>
class B{
/* some code */
};
But to use this, I always have to supply 2 parameters to B, which would work, but is inconvenient.
In c++17 using auto would work like this
template <auto &a>
class B{
/* some code */
};
But I have to work with the arm-none-eabi-gcc which apparently does not support c++17.
So I'd like to know, if there is any other way of creating such a template, so that B only needs 1 template argument.
If I understood you correctly, the goal is to get the template argument of A and make sure that the type B is instantiated with is actually an A. You can do this with some simple metaprogramming by defining your own type traits for A.
#include <type_traits>
template <int n>
class A {};
template <typename T>
struct is_A : std::false_type {};
template <int m>
struct is_A<A<m>> : std::true_type {
static constexpr int const n = m;
};
template <typename A>
class B {
static_assert(is_A<A>::value,"!");
static constexpr int const n = is_A<A>::n;
};
int main() {
B<A<1>>{};
}
Live example
I am currently struggling with templates: I have a templated class A, which performs basic math (for floats, doubles, complex numbers) and looks like this
template <typename T>
class A
{
public:
void foo(std::vector<std::complex<T>>& result);
};
Now I can use the class like A<double>, A<float>, but I would also like to use it like A<std::complex<float>> and A<std::complex<double>>. When using the latter, I would like the definition of foo to look like
void foo(std::vector<std::complex<float>>& result);
and not like
void foo(std::vector<std::complex<std::complex<float>>>& result);
Is there any way to create a specific template for the std::complex<T> cases, in which I can access the "inner" type? Or this is not possible/bad practice?
What is the most elegant way to solve this issue?
Another way can pass through the creation of a type traits to detect the (extract, when needed) the float type
template <typename T>
struct getFloatType
{ using type = T; };
template <typename T>
struct getFloatType<std::complex<T>>
{ using type = T; };
and use it in A (see fT)
template <typename T>
class A
{
public:
using fT = typename getFloatType<T>::type;
void foo(std::vector<std::complex<fT>>& result)
{ }
};
You can make a partial specialization for any instantiation of std::complex, e.g.
template <typename T>
class A<std::complex<T>>
{
public:
void foo(std::vector<std::complex<T>>& result);
};
Then for A<std::complex<double>>, the signature of foo would be void foo(std::vector<std::complex<double>>& result);.
To handle those duplicated codes, you can make a base class and move the common members into it, and make the primary template and partial specialization both derive from it. e.g.
class Base {
public:
void bar(...);
};
then
template <typename T>
class A : public Base {
...
};
template <typename T>
class A<std::complex<T>> : public Base {
...
};
I have a class looking like
template <typename T> class CClass
{
public:
struct NamedCtor;
CClass(T a, T b, T c);
private:
// data members
};
tepmlate <typename T> CClass<T>::NamedCtor : CClass<T> { NamedCtor(T x) : CClass(x, x, x) {}; };
With CClass<T>::NamedCtor() as named constructor.
This is perfectly usable if I know the template parameter when using with CClass<int>::NamedCtor(3).
But if I do not know the template parameter here, for example when I'm in a template function, I have to write something like typename CClass<T>::NamedCtor(3) with the template parameter T of the function.
Is there any way to bypass this typename as I don't really like it?
Is there a partial specialization for template class method?
template <class A, class B>
class C
{
void foo();
}
it doesn't work to specialize it like this:
template <class A> void C<A, CObject>::foo() {};
Any help?
If you are already have specialized class you could give different implementation of foo in specialized class:
template<typename A, typename B>
class C
{
public:
void foo() { cout << "default" << endl; };
};
template<typename A>
class C<A, CObject>
{
public:
void foo() { cout << "CObject" << endl; };
};
To specialize member function in Visual C++ 2008 you could make it template too:
template<typename A, typename B>
class C
{
template<typename T>
void foo();
template<>
void foo<CObject>();
};
The solution above seems to will be available only in future C++ Standard (according to draft n2914 14.6.5.3/2).
I think there is a misunderstanding there.
There are two kinds of templates:
the template classes
the template methods
In your example, you have a template class, which of course contains some methods. In this case, you will have to specialize the class.
template <class A>
class C<A,CObject>
{
void foo() { ... } // specialized code
};
The problem in your example is relatively simple: you define the method foo for the specialization C but this specialization has never been declared beforehand.
The problem here is that you have to fully specialize your C class (and thus copying a lot of data). There are a number of workarounds.
Inheritance (Composition ?): do all the common work in a base class, then have the C class inherits and specialize as appropriate
Friend: instead of having the 'foo' method being a member of C, define it as a friend free functions and specialize only this method
Delegation: have your 'foo' method call another method 'bar', which is a free function, and specialize 'bar' appropriately
Which in code gives:
// 1- Inheritance
template <class A, class B>
class CBase
{
// Everything that does not require specialization
};
template <class A, class B>
class C: public CBase<A,B>
// depending on your need, consider using another inheritance
// or even better, composition
{
void foo(); // generic
};
template <class A>
class C<A,CObject> : public CBase<A,CObject>
{
void foo(); // specialized
};
// 2- Friend
// note the change in signature:
// - now you need to pass the attributes to be changed
// - the last parameter helps differentiating the overload
// as there is no specialization for functions
template <class A, class B> void foo(Arg1&, Arg2&, const B&);
template <class A> void foo(Arg1&, Arg2&, const CObject&);
template <class A, class B>
class C
{
friend template <class, class> foo;
};
// 3- Delegation
// same signature as foo in (2)
template <class A, class B> void bar(Arg1&, Arg2&, const B&);
template <class A> void bar(Arg1&, Arg2&, const CObject&);
template <class A, class B>
class C
{
void foo() { bar(member1, member2, B()); }
};
Hope it clarifies, and helps!
No, there is no partial function template specialization in C++0x to be added.
As correctly mentioned above, with regards to function templates basically 2 things were done:
default template arguments were made available;
variadic templates were introduced.
So as before, workarounds should be used to "emulate" partial function templates specialization.
Since the class is the template, you need to specialize that:
template <class A>
class C<A, CObject>
{
void foo() { ... }
}
If I remember correctly, you cannot make partial template specialization for functions. Not sure whether it is included in C++0X
Update:
(Awaiting confirmation) As noted in the comments, partial template specialization of functions is possible in C++0X.
A method template may delegate to (static) methods of partially specialized classes or structs. Template parameters in the outer class are not helpful for answering the question.
class ClassWithSpecializedMethodEmulation
{
private:
template <typename A, typename B> struct Calculator;
public:
template <typename A, typename B> A evaluate(A a, B b)
{
return Calculator<A,B>::evaluate(a,b);
}
private:
template <typename A, typename B> struct Calculator
{
// Common case: multiply
static A evaluate(A a, B b)
{
return (A)(a*b);
}
};
// with double argument a do something else
template <typename B> struct Calculator<double, B>
{
static double evaluate(double a, B b)
{
return (double)(a - b);
}
};
};
In case the method requires access to class members, struct Calculator additionally must be friend of ClassWithSpecializedMethodEmulation and get a this-pointer passed.