c++ - 传递大小限制为可扩展大小集的 std::array 参数

标签 c++ templates c++14 stdarray

如何最好地实现接受两个 std::array<int, [size]> 的单个函数参数,每个参数的大小都由编译时已知的一组相应值约束

  • 该函数必须只接受大小从给定集合(枚举/宏/等)派生的数组
  • 允许的数组“大小”集将来可能会更改并且可能会很大(有效地排除函数重载)
  • 无论允许的数组“大小”集发生什么变化,函数本身都应该保持不变

问题“Passing a std::array of unknown size to a function”虽然相似,但似乎并不直接适用。

以下在 C++14 中有效,但似乎不必要地冗余和困惑:

#include <type_traits>
#include <array>

// Add legal/allowable sizes for std::array<> "types" here
// Note: Not married to this; perhaps preprocessor instead?
enum class SizesForArrayX : size_t { Three = 3, Four, Forty = 40 };
enum class SizesForArrayY : size_t { Two = 2, Three, EleventyTwelve = 122 };

// Messy, compile-time, value getter for the above enum classes
template <typename S>
constexpr size_t GetSizeValue(const S size)
{ return static_cast<std::underlying_type_t<S>>(size); }

// An example of the function in question; is Template Argument Deduction
//  possible here?
// Note: only arrays of "legal"/"allowable" sizes should be passable
template <SizesForArrayX SX, SizesForArrayY SY>
void PickyArrayHandler(
    const std::array<int, GetSizeValue(SX)>& x,
    const std::array<int, GetSizeValue(SY)>& y)
{
    // Do whatever
    for (auto& i : x) i = 42;
    for (auto& i : y) while (i --> -41) i = i;
}

调用上面的:

int main()
{
    // Declare & (value-)initialize some arrays
    std::array<int, GetSizeValue(SizesForArrayX::Forty)> x{};
    std::array<int, GetSizeValue(SizesForArrayY::Two>) y{};

    //PickyArrayHandler(x, y); // <- Doesn't work; C2672, C2783

    // This works & handles arrays of any "allowable" size but the required
    //  template params are repetitions of the array declarations; ick
    PickyArrayHandler<SizesForArrayX::Forty, SizesForArrayY::Two>(x, y);
}

...这是丑陋的、不优雅的、编译速度慢的,并且要求声明的数组大小与传递给 PickyArrayHandler 的显式“大小”相匹配函数模板。

  1. 对于上面的具体例子:有没有办法把PickyArrayHandler用于推断传递的数组大小的模板?

  2. 一般来说:是否有更好的不同方法?

最佳答案

由于您似乎对如何定义有效大小并不挑剔,因此可以使用类型特征

#include <array>

template <size_t N> struct valid_size1 { enum { value = false }; };
template <size_t N> struct valid_size2 { enum { value = false }; };

template <> struct valid_size1<3> { enum { value = true }; };
template <> struct valid_size1<4> { enum { value = true }; };
template <> struct valid_size1<40> { enum { value = true }; };

template <> struct valid_size2<2> { enum { value = true }; };
template <> struct valid_size2<122> { enum { value = true }; };

template <size_t TX, size_t TY>
void PickyArrayHandler(const std::array<int, TX> &x,
                       const std::array<int, TY> &y)
{
  static_assert(valid_size1<TX>::value, "Size 1 is invalid");
  static_assert(valid_size2<TY>::value, "Size 2 is invalid");
    // Do whatever
}

int main()
{
    // Declare & (value-)initialize some arrays
    std::array<int, 40> x{};
    std::array<int, 2> y{};

    PickyArrayHandler(x, y);
    PickyArrayHandler(std::array<int, 4>{}, std::array<int, 2>{});
    // PickyArrayHandler(std::array<int, 1>{}, std::array<int, 5>{}); // BOOM!
}

这是一个使用数组的解决方案:

#include <iostream>
#include <array>

constexpr size_t valid_1[] = { 3, 4, 40 };
constexpr size_t valid_2[] = { 2, 122 };

template <size_t V, size_t I=0> 
struct is_valid1 { static constexpr bool value = V==valid_1[I] || is_valid1<V,I+1>::value; };

template <size_t V, size_t I=0> 
struct is_valid2 { static constexpr bool value = V==valid_2[I] || is_valid2<V,I+1>::value; };

template <size_t V>
struct is_valid1<V, sizeof(valid_1)/sizeof(valid_1[0])>
{static constexpr bool value = false; };

template <size_t V>
struct is_valid2<V, sizeof(valid_2)/sizeof(valid_2[0])>
{static constexpr bool value = false; };

template <size_t TX, size_t TY>
void PickyArrayHandler(const std::array<int, TX> &x,
                       const std::array<int, TY> &y)
{
  static_assert(is_valid1<TX>::value, "Size 1 is invalid");
  static_assert(is_valid2<TY>::value, "Size 2 is invalid");
    // Do whatever
}

关于c++ - 传递大小限制为可扩展大小集的 std::array 参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50360264/

相关文章:

c++ - 接受另一个模板参数的模板模板集合

c++ - 指向引用的指针是非法的

c++ - 单例实例作为静态字段与 getInstance() 方法中的静态变量

c++ - 在 Cygwin 上编译 native wxWidgets 应用程序

c++ - 访问指针句柄中对象的地址

c++ - 是否可以使用 boost::filter_iterator 进行输出?

c++ - 从编译时已知大小的文字构造类似对象的字符串

c++ - 使用 setw() c++ 格式化

javascript - knockout renderTemplate() 渲染模式

c++11 限制允许的模板参数类型的首选方法