Call templated class with multiple parameters with single parameter only - c++

I have a class with multiple template parameters; let us say it looks something like this:
template <class T, class B>
struct Vector2 : B
{
Vector2() noexcept;
constexpr explicit Vector2(T a) noexcept;
}
Template parameter B always depends on T. For example if T is float B will be XMFLOAT2, if T is int B will be XMINT2. For this I created a template specialization:
template class Vector2<float, XMFLOAT2>;
template class Vector2<int32_t, XMINT2>;
template class Vector2<uint32_t, XMUINT2>;
The problem is that since B always depends on T, I want to call Vector<float> for example, and the expression should expand to Vector<float, XMFLOAT2>.
I thought of doing a typealias, however, I wouldn't be sure how to accomplish this, since it would need to be specialized again.
template<class T> using Vector2 = Vector2<T, ??>;
That doesn't really make sense...
How can I call a class with multiple template parameters using just a single parameter with the others being deduced? Or is there a different approach?

You can create helper trait:
template <typename T>
struct vector_base_class;
template <> struct vector_base_class<float> { using type = XMFLOAT2; };
template <> struct vector_base_class<int32_t> { using type = XMINT2; };
template <> struct vector_base_class<uint32_t> { using type = XMUINT2; };
template <class T>
struct Vector2 : typename vector_base_class<T>::type
{
Vector2() noexcept;
constexpr explicit Vector2(T a) noexcept;
};

As mentioned in a comment, you are probably looking for a trait:
template <typename T>
struct xm_from_T;
template <class T, class B = typename xm_from_T<T>::type>
struct Vector2 : B
{
Vector2() noexcept;
constexpr explicit Vector2(T a) noexcept;
};
Then specialize the trait:
template <> struct xm_from_T<float> { using type = XMFLOAT2; };
template <> struct xm_from_T<int32_t> { using type = XMINT2; };
template <> struct xm_from_T<uint32_t> { using type = XMUINT2; };

Related

Inheritance of user defined types in templated definitions

My understanding is that in C++ user defined types are inherited and indeed this seems to be the case up to a point.
Here is what I'm trying to do but this doesn't compile:
template <typename T>
struct A{
using type = T;
};
template <typename T>
struct B: A<T>{
using type2 = type;
};
However, if I have B extend A of a non template parameter it works:
template <typename T>
struct A{
using type = T;
};
template <typename T>
struct B: A<int>{
using type2 = type;
};
Indeed, one work around I found (but which doesn't really help me for what I'm trying to do is to scope type but this defeats the point of inheritance:
template <typename T>
struct A{
using type = T;
};
template <typename T>
struct B{
using type2 = A<T>::type;
};
Is there a proper way to achieve the behavior I want (in a more general case, this is obviously a toy example) and what are the semantics of this?
Edit: this is what I wish the code would look like, the lack of inheritance can be worked around but I wanted to understand what the limitations are
template <typename t>
struct instruction{
public:
using input = t::first;
using mem = t::second;
using newmem = mem;
using newinput = input;
using result = pair<newinput, newmem>;
};
template <typename t>
struct right_code: public instruction<t>{
using newmem = buffer<cons<mem::list2::head, mem::list1>, (std::is_same<mem::list2::tail , nil> ? cons<zero, nil>
: mem::list2::tail)>;
};
template <typename t>
using right = right_code<t>::result;
template <typename t>
struct left_code:instruction<t>{
using newmem = (std::is_same<mem::list1::tail, nil ? mem
: buffer<mem::list1::tail, cons<mem::list1::head, mem::list2>);
};
template <typename t>
using left = left_code<t>::result;
Use typename A<T>::type.
template <typename T>
struct A {
using type = T;
};
template <typename T>
struct B : A<T> {
using type2 = typename A<T>::type;
};
using type2 = type would not work for struct B : A<T> because type is a non-dependent name thus name lookup would not be affected by declarations visible on instantiation, see
https://en.cppreference.com/w/cpp/language/unqualified_lookup
For example,
template <typename T>
struct A {
using type = T;
};
template <>
struct A<int> : public C<int> {
// it doesn't need to have `type`
};
A<T> doesn't even need to have type for some specialization. We see that declarations from A<T> are unsure until we instantiate it.
By using typename A<T>::type, we make a dependent name on T, which kind of "postponed" the ​name lookup to the point of instantiation.
On the contrast, for struct B : A<int>, using type2 = type works totally fine since A<int> is explicitly instantiated so that A<int>::type is visible from the template definition context.

If template parameter AA is a templatized class A<T> itself, is it possible to get the template parameter (T) of this templatized class?

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;

Template specializations for inner class

consider the following code :
struct X
{
template <typename T>
class Y
{};
};
template<>
class X::Y<double>{
};
here we are specializing the Y class for the type double and the code works fine. the problem is that if I change the code to this:
template<typename A>
struct X
{
template <typename T>
class Y
{};
};
template<typename A>
class X<A>::Y<double>{
};
the compiler will report an error:
'X::Y': explicit specialization is using partial
specialization syntax, use template <> instead!
dose any one know how can I specialize class Y in this case?
You cannot specialize an inner template class without explicitly specializing the outer one as well. See this question for more details and a quote from the standard.
Workaround: create an outer class that takes both T and A in a detail namespace, and alias it inside X:
namespace impl
{
template <typename A, typename T>
struct Y { };
}
template<typename A>
struct X
{
template <typename T>
using Y = impl::Y<A, T>;
};
If you are fine with explicitly specializing both inner and outer class, you can use the following syntax:
template <>
template <>
class X<int>::Y<double>
{
// ...
};
Example on wandbox
The simple answer - you can't fully specialize templated inner class of templated outer class. But if you really want to achieve similar effect you could try partial specialization with dummy defaulted template parameter:
#include <iostream>
template<typename A>
struct X
{
template <typename T, T* =nullptr>
class Y{};
};
template<typename A>
template<double *Ptr>
class X<A>::Y<double, Ptr> {
public:
static constexpr int value = 1;
};
int main() {
std::cout << X<int>::Y<double>::value << std::endl;
}
[live demo]

How to use enable_if as template parameter with specialization

Why the second function can't match the template in the class definition??
Class C {
template <typename T, typename T2 = T>
T val() const;
};
template <>
std::string C::val() const {
//OK
}
template <typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type>
T C::val() const {
//Not OK
}
EDIT:
This is an overview of what I want to achieve. Basically I'm writing a function to parse and return an object based on the template type. I have some defined classes of my own, that is I have to parse with respect to their members. I also need to parse numerical types and to strings. So I wrote a specialized version for every of my defined classes. A version that parses to numerical types and return the given type (of course I have to make sure that the given type is numerical, hence the enable if)
To utilize SFINAE, use it in the template declaration, not specialization:
class C {
template <typename T, typename T2 = typename std::enable_if<std::is_arithmetic<T>::value>::type>
T val() const;
};
If you want to differentiate between arithemtic and non-arithmetic types (allowing both), you can utilize tagging:
class C {
public:
struct arithmetic_tag {};
struct non_arithmetic_tag {};
template <typename T>
T val(typename std::conditional<std::is_arithmetic<T>::value, arithmetic_tag, non_arithmetic_tag>::type tag = {}) const
{
return get_val<T>(tag);
}
private:
template <typename T>
T get_val(C::non_arithmetic_tag) const;
template <typename T>
T get_val(C::arithmetic_tag) const;
};
Or delegate the specialization to a helper class:
class C {
public:
template <typename T>
T val() const
{
return ValGetter<T>::get(this);
}
private:
template <typename T, bool is_arithmetic = std::is_arithmetic<T>::value>
struct ValGetter;
};
// Arithmetic
template <typename T>
struct C::ValGetter<T, true>
{
static T get(C const* c);
};
// Non-arithmetic
template <typename T>
struct C::ValGetter<T, false>
{
static T get(C const* c);
};
EDIT: partial specializations (bool parameter) do not work for methods, shown tagging and helper classes instead

template named constructor struct omit typename

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?