0

Is there a way to have a template class such as this

template<bool state = true>
class A
{
};

and have another class which can accept both A<true> and A<false> as a argument or field, without being a template class itself. Like this:

class B
{
public:
    B(A& arg_a)
       : a(arg_a)
    {}

private:
    A& a;
};

int main()
{
    A<true> aTrue;
    A<false> aFalse;
    B bTrue(aTrue);
    B bFalse(aFalse);
};

Or is this simply impossible because two objects of the same class with different template arguments are treated as different types by the compiler? Other suggestions on how to design this would also be appreciated. I know this design is possible if I just make the template parameter a class field, but I'd like to know if this can be done using templates parameters.

hgreen
  • 15
  • 4
  • *Or is this simply impossible because two objects of the same class with different template arguments are treated as different types by the compiler?* Correct. – NathanOliver Nov 24 '20 at 13:49
  • maybe it helps to have `using typeA = A;` and `using typeB = A;` now you can ponder about how to pass `typeA` and `typeB` to the same method. – 463035818_is_not_an_ai Nov 24 '20 at 13:51

1 Answers1

2

Or is this simply impossible because two objects of the same class with different template arguments are treated as different types by the compiler?

The two different specializations A<true> and A<false> of the class template A are indeed different types.

You could either overload the constructors of B to allow each of them:

struct B {
    B(const A<true>&);
    B(const A<false>&);
}

or you could leverage polymorphism with any specialization of A deriving from a common base class:

#include <ios>
#include <iostream>

struct Base {
    virtual bool getState() const = 0;
};

template<bool state = true>
struct A : public Base {
    bool getState() const override { return state; }
};

struct B {
    bool state;
    B(const Base& base) : state(base.getState()) {}
};

int main() {
    A<true> a1{};
    A<false> a2{};
    std::cout << std::boolalpha 
        << B(a1).state << " "  // true
        << B(a2).state;        // false
}

Another alternative, as mentioned by @Jarod42 in the comments, is to use std::variant, given that you are using C++17 (or later); particularly, std::variant<A<true>, A<false>>.

dfrib
  • 70,367
  • 12
  • 127
  • 192