为什么不能将作为常量引用传递给函数的数组的 .size() 用作模板参数?

Why can't the .size() of an array passed to a function as a constant reference be used as a template parameter?

我似乎无法弄清楚为什么以下代码不起作用:

#include <array>

template <long unsigned int s> void a() {}

template <long unsigned int s> void b(const std::array<int, s>& arr) {
    a<arr.size()>(); // error: no matching function for call to 'a'
}


int main() {
    const std::array<int, 2> arr {{0, 0}};
    a<arr.size()>(); // Works
    b<arr.size()>(arr);
    return 0;
}

GCC 失败并显示以下内容:

test.cpp: In instantiation of ‘void b(const std::array<int, s>&) [with long unsigned int s = 2]’:
test.cpp:13:22:   required from here
test.cpp:6:18: error: no matching function for call to ‘a<(& arr)->std::array<int, 2>::size()>()’
    6 |     a<arr.size()>(); // Doesn't
      |     ~~~~~~~~~~~~~^~
test.cpp:3:37: note: candidate: ‘template<long unsigned int s> void a()’
    3 | template <long unsigned int s> void a() {}
      |                                     ^
test.cpp:3:37: note:   template argument deduction/substitution failed:
test.cpp:6:18: error: ‘arr’ is not a constant expression
    6 |     a<arr.size()>(); // Doesn't
      |     ~~~~~~~~~~~~~^~
test.cpp:6:15: note: in template argument for type ‘long unsigned int’
    6 |     a<arr.size()>(); // Doesn't
      |       ~~~~~~~~^~

我假设 ‘arr’ is not a constant expression 部分是最相关的,但我不明白为什么同一行在 main() 中有效(那里是常量表达式吗?),以及为什么传递 arr 作为 const 副本(而不是参考)也解决了这个问题。

PS:我知道我可以直接使用 a<s>();,但我只是想弄清楚这个错误是什么意思。

  1. 也许在 C++2X 中,它将与 consteval 函数一起工作。

  2. 对于非引用参数它有效 https://godbolt.org/z/Wx9va54z5。 我认为一般来说按值传递 std::array 的内置函数是可以的。 (这适用于 GCC 和 clang。)

#include <array>

template <long unsigned int s> void a() {}

template <long unsigned int s> void b(std::array<int, s> arr) {
    a<arr.size()>(); // ok
}

int main() {
    const std::array<int, 2> arr = {};
    a<arr.size()>(); // Works
    b<arr.size()>(arr);
    return 0;
}
  1. 要回答您评论@acumandr 中的问题,是的,staticconstexpr size() 成员函数 std::array 可以工作(!),即使const& 参数。 https://godbolt.org/z/anP1e9qEr

CORRECTION: This is correct only for GCC, in clang doesn't work https://godbolt.org/z/65d5G9Yfo , Thanks @IlCapitano

#include <array>

template<class T, std::size_t D>
struct MyArray{
    static constexpr std::size_t size(){return D;}
};

template <long unsigned int s> void a() {}

template <long unsigned int s> void b(MyArray<int, s> const& arr) {
    a<arr.size()>(); // ok
}

int main() {
    const MyArray<int, 2> arr = {};
    a<arr.size()>(); // Works
    b<arr.size()>(arr);
    return 0;
}

这更令人困惑为什么 std::array 没有静态(和 constexpr)size 成员。

2.5) 更正:这仅适用于 GCC,在 clang 中不起作用 https://godbolt.org/z/65d5G9Yfo,谢谢 @IlCapitano

在 clang 中,静态函数有效但不传递实例,这违背了目的:

https://godbolt.org/z/En13aEWPz

#include <array>

template<class T, std::size_t D>
struct MyArray{
    static constexpr std::size_t size(){return D;}
};

template <long unsigned int s> void a() {}

template <long unsigned int s> void b(MyArray<int, s> const& arr) {
    a<std::decay_t<decltype(arr)>::size()>(); // error: no matching function for call to 'a'
}

int main() {
    const MyArray<int, 2> arr = {};
    a<arr.size()>(); // Works
    b<arr.size()>(arr);
    return 0;
}
  1. 使用std::tuple_size<decltype(...)>(或s本身)是一个很好的解决方法https://godbolt.org/z/K9xxKa1Px
#include <array>

template <long unsigned int s> void a() {}

template <long unsigned int s> void b(std::array<int, s> arr) {
    a<std::tuple_size<decltype(arr)>::value /*or just s*/>(); // ok
}

int main() {
    const std::array<int, 2> arr = {};
    a<arr.size()>(); // Works
    b<arr.size()>(arr);
    return 0;
}