我正在嘗試擴展std::span以檢查邊界operator[](我知道gsl::span提供了這個)
我已宣告我的容器如下:
#include <span>
#include <string>
#include <utility>
#include <stdexcept>
template <typename ... TopArgs> class BoundsSpan : private std::span<TopArgs...> {
public:
typename std::span<TopArgs...>::reference operator[](std::size_t idx) const {
if (idx >= this->size()) [[unlikely]] {
throw std::out_of_range(std::string("span out of bounds access detected - wanted index [" std::to_string(idx) "] but size is "
std::to_string(this->size())));
}
return std::span<TopArgs...>::operator[](idx);
}
template<typename ... Args>
BoundsSpan(Args&& ... args) : std::span<TopArgs...>(std::forward<Args>(args) ...) {}
};
這似乎很有效,但是我注意到模板引數推導不再有效。例如
int main(int argc, char *argv[]) {
BoundsSpan span(argv, argc);
}
給出了“類模板‘span’的模板引數太少”,需要一個顯式的BoundsSpan<char*>替代 - 這不是常規的情況std::span
此外,BoundsSpan在具有運行時長度的 C 樣式陣列上構造 a會給出“可變修改的型別不能用作模板引數” - 我是否在這里忽略了模板專業化?一個示例復制器是
void func(int len) {
int arr[len];
BoundsSpan<int> span(arr, len);
}
uj5u.com熱心網友回復:
std::span 模板引數串列與您的可變引數串列不兼容。它需要:
template <typename T, std::size_t N>
class span {...};
但是,您的班級正在使用可變引數型別串列。當需要非型別模板引數時,您無法將模板引數“向上”傳播到跨度基礎,并且您只能傳遞型別。最好嘗試匹配您要模擬的跨度的模板簽名。這給問題帶來了一些簡化:
您可以將所有跨度建構式公開為您自己的(即
using std::span<T, N>::span;)您可以使用與 std::span 相同的推導指南,為您的班級重命名。
這是我發現可以運行的代碼的修訂版本:
template <class T, std::size_t N = std::dynamic_extent>
class BoundsSpan : private std::span<T, N> {
public:
using std::span<T, N>::span;
using std::span<T, N>::data;
using std::span<T, N>::size;
// .. and all the other interface functions
typename std::span<T, N>::reference operator[](std::size_t idx) const {
if (idx >= this->size()) [[unlikely]] {
throw std::out_of_range("span out of bounds - wanted index ["
std::to_string(idx) "] but size is " std::to_string(size()));
}
return std::span<T, N>::operator[](idx);
}
};
然后采用 std::span 的演繹指南獲取靈感收益:
template <class It, class EndOrSize>
BoundsSpan(It, EndOrSize) -> BoundsSpan<std::remove_reference_t<std::iter_reference_t<It>>>;
template<class T, std::size_t N>
BoundsSpan(T (&)[N]) -> BoundsSpan<T, N>;
template<class T, std::size_t N>
BoundsSpan(std::array<T, N>&) -> BoundsSpan<T, N>;
template<class T, std::size_t N>
BoundsSpan(const std::array<T, N>&) -> BoundsSpan<const T, N>;
template<class R>
BoundsSpan(R&&) ->
BoundsSpan<std::remove_reference_t<std::ranges::range_reference_t<R>>>;
有了這個,它應該適用于您的示例和跨度。您可能還想包裝constoperator[]的版本。
https://godbolt.org/z/7ec3PYe7e
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/333135.html
