Я экспериментирую с шаблонами на C++, реализуя библиотеку линейной алгебры, поэтому этот пример может не подойти для этой работы лучше всего.
Допустим, у меня есть N-мерный контейнер, который содержит данные и общие функции векторов и матриц, от которых я хочу наследовать (я знаю, что общепринятой практикой является определение типа матрицы, а затем использование объявления using
для различных линейных алгебр. типы, как в собственном, но я хочу наследовать этот контейнер, а затем добавлять методы к различным типам. Опять же, это может быть не лучшим вариантом, но это эксперимент).
template <typename T, std::size_t... Dims>
class NDimContainer {
public:
auto operator+=(const NDimContainer &other) {
std::transform(elems.begin(), elems.end(), other.begin(), std::plus<T>());
return *this;
}
private:
std::array<T, (... * Dims)> elems;
};
template <typename T, std::size_t Dims>
class Vector : public NDimContainer<T, Dims> { ... }
Вопрос в следующем: можно ли получить доступ к аргументам шаблона N
и Dims...
, указанным в шаблоне шаблона, следующим образом:
template <template<typename N, std::size_t... Dims> typename T>
require std::is_derived_from<NDimContainer<N, Dims...>, T<N, Dims...>>
auto operator+(const T &lhs, const T& rhs) {
return T { lhs } += rhs;
}
Я знаю, что это возможно сделать:
template <template<typename, std::size_t...> typename T, typename N, std::size_t... Dims>
require std::is_derived_from<NDimContainer<N, Dims...>, T<N, Dims...>>
auto operator+(const T &lhs, const T& rhs) { ... }
Но тогда шаблон не будет сопоставлен, например. Vector
напечатайте (по крайней мере, в моем случае это не так, если это какая-то банальная ошибка, пожалуйста, поправьте меня).
Есть ли способ заставить эту работу работать так, чтобы я мог сделать что-то подобное?
Vector<int, 3> a = Vector<int, 3>() + Vector<int, 3>();
Предыдущие вопросы по этой теме я нашел здесь и здесь. Но ни один из них на самом деле не решает мой вариант использования.
Виновником, который запрещает гораздо более простое решение, является Dims...
, потому что я не знаю, как сделать что-то вроде этого:
template <typename T, std::size_t... Dims>
class A {
public:
using Type = T;
using Dimensions = Dims...; // Error
};
Вероятно, можно было бы использовать std::integer_sequence, но это потребует дополнительных затрат на пространство, которые я не хочу платить.
Я пробовал что-то вроде этого:
template <template<typename N, std::size_t... Dims> typename T, typename NN = N, std::size_t... DDims = Dims>
require std::is_derived_from<NDimContainer<N, Dims...>, T<N, Dims...>>
auto operator+(const T &lhs, const T& rhs) { ... }
Но это, очевидно, тоже не сработало.
Возможна ли подобная конструкция?
изменить: добавление минимального воспроизводимого примера
#include <array>
#include <concepts>
template<typename T, std::size_t ... Dims>
struct A {
std::array<T,(Dims*...)> data = {};
A& operator+=( const A& ) noexcept;
};
// This is the one I would like it matched instead, because then it would be instantiated for
// particular type.
template<template<typename N, std::size_t... Dims> typename T>
requires std::derived_from<A<N, Dims...>, T<N, Dims...>>
auto operator+(const A<N, Dims...>& lhs, const A<N, Dims...>& rhs) -> A<N, Dims...> {
return A{lhs} += rhs;
}
template<typename T, std::size_t N>
struct Vector : A<T,N> {
using Base = A<T,N>;
Vector() = default;
Vector(const Base& base) : Base(base) {}
};
using Vector3d = Vector<double,3>;
int main() {
Vector3d vec = Vector3d{} + Vector3d{};
return 0;
}
Примечание: вас может заинтересовать std::mdspan (C++23) или (реализация библиотеки C++14/17). Смотрите Многомерный C++ — Брайс Адельштейн Лелбах — CppNorth 2022
Также составьте минимальный воспроизводимый пример со всеми #include
s
«Наверное, можно было бы использовать std::integer_sequence
, но это потребует дополнительных затрат места» — using Dimensions = std::integer_sequence<Dims...>;
не занимает места
Я привел минимальный воспроизводимый пример, но это был скорее теоретический вопрос. @TedLyngmo, честно говоря, я еще не закончил с этим, и это может даже решить мою проблему, отличная идея, я был зациклен на идее сохранить последовательность в переменной.
Всегда публикуйте полную ошибку вместе с вашим вопросом. Сейчас в коде много ошибок. По сути, опубликуйте минимальный воспроизводимый пример, который воспроизводит указанную ошибку, вместо публикации кода, который компилируется. Я пытаюсь исправить ошибки в коде, но кажется, что глупых ошибок слишком много. Как будто в C++ нет is_derived_from
, вместо этого должно быть derived_from
Хорошо, я изменил пример, чтобы он выглядел именно так, как я себе представлял, как может выглядеть код. Но опять же, у меня нет проблем с конкретным фрагментом кода. Мне было интересно, можно ли ссылаться на аргументы шаблона N
и Dims
.
Ваш вопрос слишком длинный и в нем слишком много вопросов. Я сосредоточусь на этом:
Вопрос в следующем: можно ли получить доступ к аргументам шаблона N и Dims..., указанным в шаблоне шаблона, следующим образом:
template <template<typename N, std::size_t... Dims> typename T> require std::is_derived_from<NDimContainer<N, Dims...>, T<N, Dims...>> auto operator+(const T &lhs, const T& rhs) { return T { lhs } += rhs; }
Нет. Здесь template <template<typename N, std::size_t... Dims> typename T>
вы говорите, что T
— это шаблон с параметрами N
и Dims...
. Вы можете создать экземпляр T
, но не можете вывести из T
значения N
и Dims...
, поскольку они являются параметрами.
То, что вы спрашиваете, похоже на: «Для функции f
, которая принимает int x
в качестве параметра, могу ли я узнать, каково значение x
?». Конечно, нет. f
— это функция, которой можно передать любой x
.
Я чувствую бессмысленное использование аргумента шаблона, как я видел это раньше. Я полагаю, вам действительно нужен тип и что-то вроде этого:
template <typename T>
require std::is_derived_from<NDimContainer<T>,T>
auto operator+(const T &lhs, const T& rhs) {
return T { lhs } += rhs;
}
Где T
— это экземпляр некоторого шаблона, который имел параметры N
и Dims..
. Если это так, то из этого экземпляра T
(типа) можно вывести параметры N
и Dim...
, такие, что T
имеет тот же тип, что и некоторые U<N,Dims...>
. Это возможно, но другой вопрос.
Извините за неясный вопрос, но вы выбрали правильный вариант, и просмотр параметров шаблона, как будто они являются параметрами функции, помог мне понять, почему это не работает. Я думаю, что это позор, потому что мне это показалось хорошо, поэтому мне было интересно, почему это не работает. Спасибо за ваш ответ.
«Можно ли получить доступ к аргументам шаблона
N
иDims
...» Нет.