Jiří Lechner Jiří Lechner - 2 months ago 6
C++ Question

templated member function and argument forwarding

I am playing with containers in my c++ playground and I encountered rather technical problem.

I am trying to implement an emplace method for the container. For now it should take an already constructed element and pass it into the allocator construct method.

I ended up with three methods, templated

emplaceA
and a couple
emplaceB1
,
emplaceB2
. All work as intended.

My problem is
emplaceA
doesn't explicitly state that
Arg
can be only
T
(that's what I want). And
emplaceB1
,
emplaceB2
provides almost the same implementation on two different places (I see it as a flaw).

Is there a workaround?

template<class T, class A> class container {
public:
using allocator_traits = typename std::allocator_traits<A>;
...
template<class Arg> void emplaceA (int n, Arg&& arg){
allocator_traits::construct(allocator_, data_+n, std::forward<Arg>(arg));};

void emplaceB1(int n, const T& t){
allocator_traits::construct(allocator_, data_+n, t);};

void emplaceB2(int n, T&& t){
allocator_traits::construct(allocator_, data_+n, std::move(t));};
...
};

Answer

To restrict a templated function, you can use sfinae to prevent unwanted types to be sent.

In the following example, we restrict your template function to be callable only if Arg is convertible to T. Note that is_convertible will work even if the two types are the same.

template<class Arg, std::enable_if_t<std::is_convertible<Arg, T>::value, int> = 0>
void emplaceA(int n, Arg&& arg){
    // ...
}

Don't forget to include the header <type_traits>


Of course, if you want to check if the type sent is strictly T, you may want to use std::is_same with the decayed type.

template<class Arg, std::enable_if_t<std::is_same<std::decay_t<Arg>, T>::value, int> = 0>
void emplaceA(int n, Arg&& arg){
    // ...
}