Ваш вопрос немного сложнее понять без примера. Я понимаю, что вы хотите специализировать конструктор шаблона класса и строить его член по-разному для разных аргументов шаблона. Если это не правильно, сообщите мне, и я отрегулирую свой ответ.
Снова без примера трудно понять, что вы делаете и не понимаете. Но в целом это делается так же, как вы бы специализируетесь на других методах. Объявите все специализации в своих заголовках и реализуйте их в своем файле реализации (если только они не являются частичными специализациями!). Не забывайте использовать template<>
, когда вы специализируетесь. Вот пример:
struct t_param_for_int {};
struct t_param_for_double {};
// t_member's constructor is very different depending on T
template<class T> struct t_member {};
template<> struct t_member<int> {
explicit t_member(const t_param_for_int value) {};
};
template<> struct t_member<double> {
explicit t_member(const t_param_for_double value) {};
};
// Foo has a t_member and a constructor
template<class T>
struct foo
{
foo();
t_member<T> member;
};
// Declare specialization
template<> foo<int>::foo();
template<> foo<double>::foo();
// Specialization implementations (in a .cpp)
template<> foo<int>::foo() : member(t_param_for_int{})
{ }
// Specialization implementations (in a .cpp)
template<> foo<double>::foo() : member(t_param_for_double{})
{ }
int main()
{
foo<int> int_foo;
foo<double> dbl_foo;
return 0;
}
Редактировать: В ответ на изменение вопроса.
Вы не можете специализировать конструктор в этом случае. Лучшим решением, вероятно, будет использование вспомогательных структур для фактической инициализации. Вы упомянули, что хотите инициализировать свои контейнеры с помощью некоторого количества 0 или построенных по умолчанию элементов T
. Однако вы не указали, насколько велики ваши контейнеры. Я построил пример, чтобы проиллюстрировать решение использования хелперных структур с использованием фиктивных размеров контейнеров.
#include <array>
#include <iostream>
#include <type_traits>
#include <string>
#include <utility>
#include <vector>
template<typename T, typename C>
struct helper_init;
template<typename T>
struct helper_init<T, std::vector<T>> {
static std::vector<T> init() {
return std::vector<T>(3, T{}); // init your vector with 3 elements
}
};
template<typename T>
struct helper_init<T, std::array<T, 2>> {
static std::array<T, 2> init() {
return {}; // init your array with 2 elements
}
};
template <typename T, typename C>
struct foo {
T m;
C container;
using value_type = typename C::value_type;
template <typename... Args>
foo(Args&&... args)
: m(std::forward<Args>(args)...)
, container(helper_init<T, C>::init())
{}
};
int main()
{
foo<int, std::vector<int>> vec_foo(5);
foo<std::string, std::array<std::string, 2>> str_foo("hello");
// Output to illustrate
// The size of the containers are 3 and 2 (see container initialization)
std::cout << vec_foo.container.size() << ' '
<< str_foo.container.size() << std::endl;
// The m members contain the assigned values
std::cout << vec_foo.m << " \'" << str_foo.m << '\'' << std::endl;
// The containers are zero or default initialized
std::cout << vec_foo.container.front() << " \'" <<
str_foo.container.front() << '\'' << std::endl;
return 0;
}
Для второй части Вашего вопроса, инициализирующей до 0 арифметических типов и значения по умолчанию для построения типов классов, языка уже есть возможность для этого.
std::array конкретно говорит об этом.
инициализируется массив следующим правилам агрегатного инициализации
aggregate initialization Тогда говорит это.
Если количество инициализаторов пунктов меньше, чем число членов или список инициализаторов полностью пуст, остальные члены значение инициализируется.
И наконец value initialization говорит об этом.
1) если T - тип класса с хотя бы одним предоставленным пользователем конструктором любого типа, вызывается конструктор по умолчанию;
4) В противном случае объект инициализируется нулем.
Это позволит нам сделать это std::array<T, 10> my_array{};
и иметь десять обнуляется или по умолчанию построены T
с. Мы также можем сделать std::vector<T> my_vector(10, T{});
, чтобы получить тот же результат (T{}
is value built`).
Редактировать 2: Вот еще одно решение, которое больше соответствует требованиям этого вопроса, используя конструктор делегирования и отправку тегов.
#include <array>
#include <string>
#include <vector>
// Tags for supported containers
struct t_tag_array {};
struct t_tag_vector {};
// Tag dispatching
template<class T, size_t S>
struct t_container_tag {};
template<class T, size_t S>
struct t_container_tag<std::vector<T>, S> {
using type = t_tag_vector;
};
template<class T, size_t S>
struct t_container_tag<std::array<T, S>, S> {
using type = t_tag_array;
};
// Helper to fetch the size of an std::array
template<typename>
struct array_size;
template<typename T, size_t S>
struct array_size<std::array<T, S>> {
static const auto value = S;
};
template <typename C, size_t S = array_size<C>::value>
struct foo
{
using value_type = typename C::value_type;
// Constructor
template<typename... Args>
foo(Args&&... args) : foo(typename t_container_tag<C, S>::type{}, std::forward<Args>(args)...) {}
// Specialized constructor for vectors
template<typename... Args>
foo(t_tag_vector &&, Args&&... args) : m(std::forward<Args>(args)...), container(S, value_type{}) {}
// Specialized constructor for arrays
template<typename... Args>
foo(t_tag_array &&, Args&&... args) : m(std::forward<Args>(args)...), container{} {}
value_type m;
C container;
};
Образец кода будет намного дальше описывать вашу проблему. Вы ищете что-то вроде этого: http://coliru.stacked-crooked.com/a/5d9ea40421963b70? – Praetorian
Я отредактирую свой ответ с примером, который вы предоставили, как только я получу эту возможность. –