迭代n维向量c++

aemubtdh  于 2023-02-01  发布在  其他
关注(0)|答案(2)|浏览(165)

我想写自己的代码来迭代一个n维向量(维度是已知的),代码如下:

void printing(const auto& i, const int dimension){
    int k= dimension;
    for(const auto& j: i){
        if(k>1){
            cout<<"k: "<<k<<endl;
            printing(j, --k);
        }
        else{
            //start printing
            cout<<setw(3);
            cout<<j; //not quite sure about this line
        }
        cout<<'\n';
    }
}

我得到一个错误:

main.cpp:21:5: error: ‘begin’ was not declared in this scope
 for(const auto& j: i){
 ^~~

有人能帮我纠正它或给我一个更好的方法来打印矢量吗?提前感谢您的时间。

xmd2e60i

xmd2e60i1#

如果维度在编译时是已知的,那么使用template将维度作为非类型参数就可以很容易地解决这个问题。

template <std::size_t Dimensions>
void printing(const auto& i){
    if constexpr (Dimensions != 0) {
        for(const auto& j: i){
            // I'm not sure if it is intentional to print 'k' each iteration, 
            // but this is kept for consistency with the question
            cout<<"k: " << Dimensions << endl;
            printing<Dimensions - 1u>(j);
        }
    } else {
        cout << setw(3);
        cout << j;
        cout << '\n';
    }
}

对于2d向量,其用途是:

printing<2>(vec);

Live Example
但是,如果您总是知道const auto& i将是std::vector类型,则可以通过根本不使用auto参数,而是使用template匹配来更容易地解决这个问题:

// called only for the vector values
template <typename T>
void printing(const std::vector<T>& i){
    for(const auto& j: i){
        // possibly compute 'k' to print -- see below
        printing(j);
    }
}

// Only called for non-vector values
template <typename T>
void printing(const T& v) {
    cout << setw(3);
    cout << v;
    cout << '\n';
}

Live Example
为了计算向量的“维数”,你可以写一个递归类型特征:

#include <type_traits> // std::integral_constant

// Base case: return the count
template <std::size_t Count, typename T>
struct vector_dimension_impl
  : std::integral_constant<std::size_t, Count> {};
 
// Recursive case: add 1 to the count, and check inner type
template <std::size_t Count, typename T, typename Allocator>
struct vector_dimension_impl<Count, std::vector<T,Allocator>> 
  : vector_dimension_impl<Count + 1u, T> {};

// Dispatcher
template <typename T>
struct vector_dimension : vector_dimension_impl<0u, T> {};

// Convenience access
template <typename T>
inline constexpr auto vector_dimension_v = vector_dimension<T>::value;
 
// Simple tests:
static_assert(vector_dimension_v<std::vector<int>> == 1u);
static_assert(vector_dimension_v<std::vector<std::vector<int>>> == 2u);
static_assert(vector_dimension_v<std::vector<std::vector<std::vector<int>>>> == 3u);

Live Example
有了上面的递归特性,就可以得到每个template d向量类型的“维数”,而根本不需要用户传入值。
如果您仍然希望每次都打印k:,您可以简单地使用上面的命令:

cout << "k: " << vector_dimension_v<T> << endl;

这仅在已知类型为vector时有效--但是也可以使用概念来编写它,以处理遵循vector之类的抽象定义的任何内容。
如果你想让它适用于 any range类型,那么你可以用requires(std::ranges::range<T>)替换vector-重载,并将用于查找维度的模板专用化修改为也使用相同的类型。我不会用所有这些代码来破坏答案,因为它与上面的代码基本相同--但我将在下面的操作中链接到它:
Live Example

flseospp

flseospp2#

我做了一个函数,可以打印任何n维可迭代容器:

template<typename Object, typename Iterable>
void Print(
    const Iterable& iterable,
    const string& separatorDimensions = "\n",
    const function<void(const Object&)>& funcPrintElem = [] (const Object& obj) {
        static_assert(
            is_arithmetic_v<Object> || is_same_v<remove_const_t<remove_pointer_t<Object>>, char>,
            R"(The object from the innermost range is not a built-in/c-string type, please provide a valid print element function.)"
            );
        cout << obj << ' ';
    }
) {
    if constexpr (ranges::range<Iterable>) {
        ranges::for_each(iterable, [&] (const auto& it) { Print(it, separatorDimensions, funcPrintElem); });
        cout << separatorDimensions;
    } else {
        funcPrintElem(iterable);
    }
}

这个函数有一个默认的std::function,可以打印任何内置类型,如intunsigned charlong long等,还有c字符串,如charconst char*,如果你有另一个对象,如pairtuple或你的类的对象,你可以传递一个函数来打印你的对象。
您可以像这样使用函数:(你必须明确地告诉函数你最里面的对象,如下所示)

int main() {
    cout << "v: " << endl;
    vector<uint16_t> v { 1, 2, 3 };
    Print<uint16_t>(v);

    cout << endl << "ll: " << endl;
    list<list<const char*>> ll { { "a", "b" }, { "c", "d" } };
    Print<const char*>(ll);

    struct smth {
        int a;
        char b;
    };

    cout << endl << "smths: " << endl;
    vector<smth> smths { { 14, '0' }, { 18, '1' } };
    Print<smth>(smths, "\n", [] (const smth& obj) { cout << "a = " << obj.a << ", b = " << obj.b << endl; });

    return 0;
}

功能可以找到here,也许我会更新在未来支持更多的东西。
编辑:你需要至少有c++20这个函数的工作

相关问题