Reputation: 3357
Suppose I have a template class:
template<typename T>
class Widget {
public:
Widget(const std::string& name, int i) : t_(name), cf_(name), ci_(i) {}
private:
T t_;
const Foo cf_;
const int ci_;
}
And suppose, in this context, T
will only be Foo
or int
. Anything other than Widget<Foo>
and Widget<int>
is nonsense in this context.
The constructor declared above works fine for Widget<Foo>
. Is there a way I can define a specialised constructor for Widget<int>
, which assigns to t_
differently, but without copy-pasting the initialisation of cf_
and ci_
?
Something similar in spirit to the call to Base(a)
in Derived::Derived(int a, int b) : Base(a), b_(b) {}
perhaps?
Upvotes: 1
Views: 59
Reputation: 118445
Specializing the entire Widget<int>
class is one option. Short of that, there are various approaches that can be used to avoid specializing the entire class; however they depend heavily on exactly how you need to construct it.
For this example, let's say that for Widget<Foo>
you want to construct the class member t_
, which will be a Widget
using the std::string name
parameter (Widget
has a constructor that takes a std::string
parameter), and for Widget<int>
you want to construct the class member t_
which will now be an int
using the int i
parameter.
First, define a specialized helper template function that picks the right parameter:
template<typename T>
auto t_param(const std::string &name, int i);
template<>
auto t_param<Foo>(const std::string &name, int i)
{
return name;
}
template<>
auto t_param<int>(const std::string &name, int i)
{
return i;
}
With this in place, your constructor becomes simply:
Widget(const std::string& name, int i)
: t_(t_param<T>(name, i)), cf_(name), ci_(i) {}
Upvotes: 1
Reputation: 217810
Tag dispatching, and forwarding constructor may help
template <typename> struct Tag {};
template<typename T>
class Widget {
public:
Widget(const std::string& name, int i) : Widget(Tag<T>{}, name, i) {}
private:
Widget(Tag<int>, const std::string& name, int i) :
Widget(Tag<void>{}, 42, name, i)
{}
Widget(Tag<Foo>, const std::string& name, int i) :
Widget(Tag<void>{}, name, name, i)
{}
template <typename U>
Widget(Tag<void>, U&& u, const std::string& name, int i) :
t_(std::forward<U>(u)),
cf_(name),
ci_(i)
{}
private:
T t_;
const Foo cf_;
const int ci_;
};
Upvotes: 5