Reputation: 3677
Lets say I have following (rather confusing example from Bjarne Stroustrup's book) template class with template member
template<class Scalar> class complex {
Scalar re, im;
public:
template<class T>
complex(const complex<T> &c) : re(c.re), im(c.im) {}
//...
}
complex<float> cf(0,0);
is one way to create object of this class, but is Scalar
deduced as float or T
is deduced as float in this example? What are some different ways to create objects of this class? I want to understand how template type is being deduced from these examples.Upvotes: 1
Views: 88
Reputation: 24269
template<class Outer>
struct S1 {
template<class Inner>
S1(const S1<Outer>& rhs) {}
};
template<class Outer>
struct S2 {
template<class Inner>
S2(const S2<Inner>& rhs) {}
};
S1<float> s1f;
S2<float> s2f;
S1<double> s1d(s1f); // error
S2<double> s2d(s2f); // ok
What's being demonstrated is deduction of a member function template parameter from the template type of a parameter.
For s2d
above, we know that Outer
is double, it's specified not deduced.
However when we pass s2f
to its constructor we are passing an object of type S2. We provide a constructor that takes S2<? Inner ?>
, so we have a container match if we deduce Inner
to be float.
What's being demonstrated is a templated class with further templated member functions. Consider:
template<class Outer>
struct S {
template<class Other>
S(const Other& rhs) {}
};
If we do
S<float> sf;
S<int> si(sf);
Here the copy constructor deduces Inner
to be not just int
but S<int>
.
Practical use:
template<class C, class T>
struct PtrContainer {
using container_type = C;
using value_type = T;
using self_type = PtrContainer<container_type, value_type>;
using ptr_type = T*;
using size = sizeof(T);
PtrContainer() : c() {}
void append(ptr_type p) {
c.push_back(p);
}
template<class D>
std::enable_if<std::is_base_of<T, D>::value, void>::type
transfer(PtrContainer<D>& rhs) {
c.insert(c.end(), rhs.c.begin(), rhs.c.end());
rhs.c.clear();
}
void clear() {
for (auto* ptr: c) {
delete ptr;
}
c.clear();
}
~PtrContainer() { clear(); }
container_type<ptr_type> c;
};
struct S {};
struct SD : public S {};
int main() {
PtrContainer<vector, S> pvs;
pvs.append(new S);
PtrContainer<list, SD> plsd;
plsd.append(new SD);
pcs.transfer(plsd);
}
Upvotes: 1
Reputation: 206717
complex<float> cf(0,0);
is one way to create object of this class, but isScalar
deduced asfloat
orT
is deduced asfloat
in this example? What are some different ways to create objects of this class? I want to understand how template type is being deduced from these examples.
In this example, nothing is deduced. Scalar
is explicitly specified as float
.
The template constructor does not get called for this.
What is the use of member templates?
Say you have:
Complex<float> c1(10, 20);
and then you want to use c1
to create another Complex
but with a different type for Scalar
.
Complex<double> c2(c1);
In this case the template constructor is used. Scalar
is explicitly specified as double
and T
is deduced as float
.
Upvotes: 1
Reputation: 96301
In your example, the code explicitly specifies Scalar
to be float
(no deduction happens). But the copy(ish) constructor you show is not the one that will be called in your subsequent example.
Upvotes: 0