2015-07-10 63 views
1

有没有一种方法来存储任何(但常量)长度的std ::数组的集合,其中的数组长度可以稍后在constexpr中使用?存储任何(但常量)长度的std ::数组的集合

我猜标准容器没有问题,但可能有某种模板解决方案。所有的信息都可以在编译时使用,不是吗?

示例代码:

#include <iostream> 
#include <string> 
#include <vector> 
#include <array> 
#include <algorithm> 

// Class storing an array of any (but constant) size 
struct A { 
    const std::vector<std::string> container; 
    const int container_size; 
    A(const std::vector<std::string>& v, int size) : container(v), container_size(size) { } 
}; 

int main() { 
    // List of variable length const arrays and their sizes 
    std::vector<A> myAList { 
     A({ std::string("String1"), std::string("String2") }, 2), 
     A({ std::string("String1") }, 1) 
    }; 

    // How would I go about using the size of each array in a constexpr? 
    for (auto const& a : myAList) { 
    // Example constexpr: 
    // somefunc(std::make_index_sequence<a.container_size>{}); 

    // 2nd example converting to actual std::array 
    // std::array<std::string, a.container_size> arr; 
    // std::copy_n(std::make_move_iterator(a.begin()), a.container_size, arr.begin()); 
    } 

    return 0; 
} 

更新:被要求

更多细节,所以这里去。我并不关心数组是如何定义的,任何可行的......使用的确切constexpr是示例代码std::make_index_sequence<CONSTEXPR>{}中的那个。 我只知道我有一组在编译时定义的常量数组,它应该以某种方式在constexpr的其他地方引用它们的长度。

哎呀,其实我是罚款只是存储长度:

// Class storing an array size 
struct A { 
    A(int size) : container_size(size) { } 
    const int container_size; 
}; 

int main() { 
    // List of lengths 
    std::vector<A> mySizeList { 2, 1 }; 

    for (auto const& a : mySizeList) { 
    // somefunc(std::make_index_sequence<a.container_size>{}); 
    } 
    return 0; 
} 
+0

的simpke答案是你不能。更复杂的答案可能归结为“可能,取决于确切的constexpr操作,以及您构建所述数组的方式以及您未包含的其他细节”,并且实现非常棘手。你只打算以这种方式调用一个特定的'somefunc'? – Yakk

+0

@Yakk'somefunc'是一个可变参数模板函数,它将参数应用于通过函数指针调用的函数。我需要一个编译时索引序列来解压参数,因此'make_index_sequence'是必需的。 – Oystein

+0

这是一个肯定还是不肯定? **“你是否只打算以这种方式调用一个特定的'somefunc'?”**我在此承认“是”,并在下面添加了一个答案。它也传递一个'const&'到'vector'以防你也需要。 – Yakk

回答

3

这是假设你要调用somefunc同时与const&std::vectorindex_sequence,而您只需要拨打somefunc 。它还支持带有扩展签名的somefunc(只需传递第三个参数,返回值和/或附加参数,它们将在std::vector<T> const&之后传递)。

如果传入的大小比传入的长度大,未能将传入的大小与传入的大小对齐将导致不良。

它还假定你知道在施工时你要调用什么功能。这可以推广到你想在施工时调用的任何有限的函数集。

使用的技术被称为“类型擦除”或“运行时概念”。我删除了在构建过程中调用some_func以及索引序列的概念,并将该删除的操作存储在f中。

template<size_t N> 
using size=std::integral_constant<size_t, N>; 

template< 
    class T, template<class...>class Operation, 
    class Sig=std::result_of_t<Operation<size<0>>(std::vector<T> const&)>() 
> 
struct eraser; 

template<class T, template<class...>class Operation, class R, class...Args> 
struct eraser<T,Operation, R(Args...)> { 
    std::vector<T> data; 
    R(*f)(eraser const*, Args&&...); 
    R operator()(Args...args)const{ 
    return f(this, std::forward<Args>(args)...); 
    } 
    template<size_t N> 
    eraser(std::initializer_list<T> il, size<N>): 
    eraser(il.begin(), size<N>{}) 
    {} 
    template<class...Ts> 
    eraser(T t0, Ts... ts): 
    eraser(
     {std::forward<T>(t0), std::forward<Ts>(ts)...}, 
     size<sizeof...(ts)+1>{} 
    ) 
    {} 
    template<size_t N> 
    eraser(T const* ptr, size<N>): 
    data(ptr, ptr+N), 
    f([](eraser const*self, Args&&...args)->R{ 
     return Operation<size<N>>{}(self->data, std::forward<Args>(args)...); 
    }) 
    {} 
}; 
template<class T, size_t ... Is> 
void some_func(std::vector<T> const&, std::index_sequence<Is...>) { 
    std::cout << "called! [#" << sizeof...(Is) << "]\n"; 
} 
template<class N> 
struct call_some_func { 
    template<class T> 
    void operator()(std::vector<T> const& v) const { 
    some_func(v, std::make_index_sequence<N{}>{}); 
    } 
}; 


int main() { 
    using A = eraser<std::string, call_some_func>; 
    // List of variable length const arrays and their sizes 
    std::vector<A> myAList { 
    A({ std::string("String1"), std::string("String2") }, size<2>{}), 
    A({ std::string("String1") }, size<1>{}) 
    }; 

    std::cout << "Objects constructed. Loop about to start:\n"; 

    // How would I go about using the size of each array in a constexpr? 
    for (auto const& a : myAList) { 
    a(); 
    } 
} 

live example

+0

那是一些漂亮的模板代码!经过大量调整并试图理解您的代码后,我最终使用了一些概念,现在它运行得非常漂亮! – Oystein

+0

我不假设您知道一种方法来优化'size{}'integral_constant定义(除了宏)吗? – Oystein

+1

'template constexpr size sz(){return {}; }'给你一个函数'sz',你可以'sz <0>()'如果你认为漂亮吗?你也可以将'std :: string's传递给'eraser'的variardic ctor,为你计算参数。所以你会得到'std :: vector myAList {{“String1”,“String2”},{“String1”}}'这看起来更漂亮。未经测试的版本添加到上面发布。 – Yakk

0

我猜你想要的东西是一样的东西dynarray这是奄奄一息。

你当然不能在常量表达式中使用它的大小,因为它不是一个编译时常量(这就是名字中的“dyn”引用的)。

要使用container_size的常量表达式类型A必须是文字型,所以它必须有一个constexpr构造函数,如果你想传递一个vector这将是非常困难的事情!

你可以做这样的事情,但它是相当恶心:

#include <array> 

struct A 
{ 
    void* ap; 
    std::size_t n; 
    template<std::size_t N> 
     constexpr A(std::array<int, N>& a) : ap(&a), n(N) { } 
    template<std::size_t N> 
     std::array<int, N>& get() const { return *static_cast<std::array<int, N>*>(ap); } 
    constexpr std::size_t size() const { return n; } 
}; 

int main() 
{ 
    static std::array<int, 3> a{ 1, 2, 3 }; 
    constexpr A aa(a); 
    constexpr int len = aa.size(); // OK, this is a constant expression 
    std::array<int, aa.size()>& r = aa.get<aa.size()>();   
} 
+0

我明白了,也许恶心是一次去... – Oystein

+0

即使看了两个现在的答案,我也不明白这个问题。我不认为我很愚蠢。 –