Ameya Deshpande
Ameya Deshpande

Reputation: 71

C++: Way around dependent templates

I have a class template like this:

    template <typename T1, typename T2>
    class ClassName {
        // Members variables and Functions based on the template parameter types
    };

(T1, T2) can either be (class A, class B) or (class C, class D) only. So, T1 alone is enough to determine T2. Is there any way to only take T1 as a parameter and write the same class? If yes, how?

Upvotes: 0

Views: 112

Answers (3)

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122133

If your template only depends on a single parameter, you should not declare it with 2 parameters. You can use std::conditional together with std::is_same to declare conditional aliases.

If you want:

(T1, T2) can either be (class A, class B) or (class C, class D) only

If "only" is meant as: User only ever instantiates for A or C and in that case T2 should be B / D:

#include <type_traits>

struct A {};
struct B {};
struct D {};

template <typename T>
struct Foo {
  using T1 = T;
  using T2 = std::conditional_t<std::is_same_v<A, T>, B, D>;
};

Foo<A>::T2 is B and Foo<C>::T2 is D. Actually Foo<T>::T2 is D for any T that is not A. In other words, as mentioned above, the premise is that it is only instantiated for either A or C. If the template itself should make sure that only instantiations for A or C are valid, you might want to add a static_assert (again using std::is_same to check that T is among the allowed types).

Upvotes: 5

Bob__
Bob__

Reputation: 12749

You can write a type trait:

#include <iostream>
#include <type_traits>

struct A {};
struct B {};
struct C {};
struct D {};

template <typename Type> struct Dependent {};

template<>
struct Dependent<A> {
    using type = B;
};

template<>
struct Dependent<C> {
    using type = D;
};


template <typename Type>
class ClassName {
    using Dependent = typename Dependent<Type>::type;
};

int main()
{
    static_assert(std::is_same<Dependent<A>::type, B>::value, "");
    static_assert(std::is_same<Dependent<C>::type, D>::value, "");
    // Dependent<B>::type a;    error: 'type' is not a member of 'Dependent<B>'  
}

Upvotes: 3

Mooing Duck
Mooing Duck

Reputation: 66912

Make an enumeration of your configurations:

enum class ClassConfigEnum { AB, CD};
template<ClassConfigEnum config> struct ClassConfig;
template<> struct ClassConfig<AB> {
    using T1 = A;
    using T2 = B;
};
template<> struct ClassConfig<CD> {
    using T1 = C;
    using T2 = D;
};

And then have the class use the enumerated configuration

template <ClassConfigEnum config>
class ClassName {
    using T1 = ClassConfig<config>::typename T1;
    using T2 = ClassConfig<config>::typename T2;
};

Upvotes: 4

Related Questions