Comments 14
Отличная статья, подход принят к сведению.
зы 2000 просмотров, 22 добавили в избранное, 0 комментариев — грустно это
зы 2000 просмотров, 22 добавили в избранное, 0 комментариев — грустно это
+2
В C++11 проблема решается проще.
template <class T, template<class, class...> class Container>
struct A {
typedef Container<T> type;
};
+8
boost::mpl вроде как хотели включить в C++11
0
template <typename T, template<typename, typename> class Container>
struct A
{
typedef Container<T, std::allocator<T> > type;
};
Можно и упростить (хотя, вряд ли это упрощение..):
template <typename T, template<typename Y, typename = std::allocator<Y> > class Container>
struct A
{
typedef Container<T> type;
};
Мы должны заглянуть в реализацию std::vector, выяснить, какой тип аллокатора используется по умолчанию, и тогда использовать его.
Зачем заглядывать — все
std
контейнеры используют std::allocator
. 0
std-контейнер был взят для примера, случай для любых контейнеров.
+1
Возможно, я ошибаюсь, но мне казалось, что стандарт не накладывает ограничение на количество параметров шаблона по-умолчанию, например в std::vector:
Тогда, предложенный Вами способ не подойдет, т.к. заранее не известно, сколько параметров у шаблона.
Поправьте меня, если я ошибаюсь.
template <typename T, typename A = std::allocator<T>, typename _P1 = def1, typename _P2 = def2, ...>
class vector;
— вполне может быть валидной сигнатурой vector.Тогда, предложенный Вами способ не подойдет, т.к. заранее не известно, сколько параметров у шаблона.
Поправьте меня, если я ошибаюсь.
+1
Вы, наверное, меня не поняли. Я имел в виду, что если уж говорить о проблеме, то зачем наводить нереальные примеры? В том плане, что
Вы абсолютно правы. Конечно, предложенный способ не подойдёт.
std::vector
и т. д. — вполне стандартизированные вещи.template <typename T, typename A = std::allocator<T>, typename _P1 = def1, typename _P2 = def2, ...>
class vector;
Вы абсолютно правы. Конечно, предложенный способ не подойдёт.
0
И тем не менее, получился код, который зависит от шаблонных параметров. А если контейнер вообще не имеет шаблонных параметров? А если у него больше одного обязательного параметра? А если это вообще не класс, а массив? Шаблоны должны писаться исходя из потребностей к контейнеру. Если минимум потребностей — это возможность обойти элементы с помощью range-based for, то код будет выглядеть примерно так:
#include <vector>
#include <map>
#include <array>
template <typename C, typename = decltype(
std::begin(std::declval<C>()), void(),
*std::begin(std::declval<C>()), void(),
std::end(std::declval<C>()), void(),
std::next(std::begin(std::declval<C>())), void())>
struct BetterA
{
typedef decltype(*std::begin(std::declval<const C>())) type;
};
void test()
{
auto test1 = BetterA<std::vector<int>>();
auto test2 = BetterA<std::map<int, int>>();
auto test3 = BetterA<int[10]>();
auto test4 = BetterA<std::array<int, 10>>();
}
0
У вас ус отклеилсяпример не компилируется. Точнее, сложности вызывает часть с
P.S. Я так понял, вы хотели вот этого?
BetterA<int[10]>
.P.S. Я так понял, вы хотели вот этого?
template <typename Cont>
struct A
{
typedef typename Cont::value_type type;
};
template <typename T, size_t N>
struct A<T[N]>
{
typedef T type;
};
void test()
{
auto test1 = A<std::vector<int>>::type();
auto test2 = A<std::map<int, int>>::type();
auto test3 = A<int[10]>::type();
auto test4 = A<std::array<int, 10>>::type();
}
0
MSVC2012 нормально компилирует. А с чего бы этому коду не компилироваться? Массив же фиксированного размера. А вот
А длинный decltype в аргументах шаблона — это SFINAE для ленивых. Нет общего класса (соответственно, не нужен enable_if), но останавливает компилятор, если контейнер нельзя обойти.
int*
, естественно, компилятор не съест.А длинный decltype в аргументах шаблона — это SFINAE для ленивых. Нет общего класса (соответственно, не нужен enable_if), но останавливает компилятор, если контейнер нельзя обойти.
0
Дело в том, что по стандарту,
Можно было бы написать что-то вроде
А, ну MSVC, как всегда, на своей волне :)
std::declval
возвращает r-value ссылку на значение, в то время как std::begin
принимает массив только по обычной ссылке, поэтому конструкцияstd::begin(std::declval<int[10]>())
не компилируется.Можно было бы написать что-то вроде
template <typename T>
const T& declval2();
template <typename C>
struct BetterA
{
typedef typename std::decay<decltype(*std::begin(declval2<const C>()))>::type type;
};
но мой изначальный вариант мне нравится больше.А, ну MSVC, как всегда, на своей волне :)
+1
Решение интересное но непрактичное. Придётся всех заставить писать std::vector<boost::mpl::_1> чтобы использовать ваш класс, и это прямо скажем неочевидно для тех кто внутрь смотреть и не собирается.
Если мы знаем что контейнер это не массив а контейнер std или boost (да и вообще большинство контейнерописателей value_type не забывают затайпдефить), то можно обойтись так(если конечно архитектура проекта позволяет):
template <typename Container>
struct AA {
typedef Container type;
typedef typename Container::value_type valueType; // то что было T в вашем случае
};
можно добавить enable_if для value_type если надо…
Ну и в случае с C++11 тут вторым комментом ответ.
Если мы знаем что контейнер это не массив а контейнер std или boost (да и вообще большинство контейнерописателей value_type не забывают затайпдефить), то можно обойтись так(если конечно архитектура проекта позволяет):
template <typename Container>
struct AA {
typedef Container type;
typedef typename Container::value_type valueType; // то что было T в вашем случае
};
можно добавить enable_if для value_type если надо…
Ну и в случае с C++11 тут вторым комментом ответ.
0
Only those users with full accounts are able to leave comments. Log in, please.
Отказываемся от шаблонных шаблонных параметров