Jaeya
Jaeya

Reputation: 141

Writing constructor of template class with template argument-depending parameters

Consider the following two classes with constructors that accept wildly different sets of parameters.

class A {
public:
  A(int x, double y) {
    //do something
  }
};

class B {
public:
  B(const std::vector<bool>& x) {
    //do something
  }
};

Now, I want to write a class template TpC that will have an object (which might be A or B or something else). In other words, I want to be able to use the following:

int x;
double y;
std::vector<bool> z;
TpC<A> obj_a (x, y);
TpC<B> obj_b (z);

How can I write a constructor for TpC that is dependent on the parameters of the constructors of A and B? It would be acceptable to write something like a trait/policy to tell TpC what the parameters should be for each particular specialization.

Upvotes: 1

Views: 2651

Answers (3)

songyuanyao
songyuanyao

Reputation: 172864

You could write a template constructor with parameter pack for TpC. (As the comments suggested I used SFINAE to constrain template, otherwise it might be better match than copy constructor. See the whole code snippet from the link I posted.)

template <typename T, typename... U>
struct my_is_same {
    constexpr static bool value = false;
};
template <typename T1, typename T2, typename... U>
struct my_is_same<T1, T2, U...> {
    constexpr static bool value = std::is_same_v<T1, std::remove_cvref_t<T2>>;
};
template <typename T, typename... U>
inline constexpr bool my_is_same_v = my_is_same<T, U...>::value;

template <typename T>
class TpC {
    T t;
public:
    template <typename... Args, typename = std::enable_if_t<
                                             !my_is_same_v<TpC, Args...> &&
                                             std::is_constructible_v<T, Args&&...>
                                           >>
    TpC(Args&& ... args) : t(std::forward<Args>(args)...) {}
};

and then

int x;
double y;
std::vector<bool> z;
TpC<A> obj_a (x, y);
TpC<B> obj_b (z);

LIVE

Upvotes: 3

flamewing
flamewing

Reputation: 89

If you are using c++11 or later, you can use a variadic template constructor with a parameter pack expansion calling std::forward on the constructor arguments. Something like:

template <typename T>
class TpC {
    T base;
public:
    template <typename... Args>
    TpC(Args&&... args)
    : base(std::forward<Args>(args)...) {
    }
};

Upvotes: -1

SergeyA
SergeyA

Reputation: 62553

You would need to use a template constructor. However, in order to prevent this constructor being called instead of the copy constructor, you need to add a bit of disambiguation. For example:

template<class T>
class TpC {
     T t;
public:
     struct in_place_t { };
     static constexpr in_place_t in_place;
     template<class... ARGS>
     TpC(in_place_t, ARGS... args) : t(std::forward<ARGS>(args)...) {}
};

In C++17 in_place is available in std.

Upvotes: 2

Related Questions